交换座位

题目描述

在一场集体婚礼上,有n对新人需要坐在连续排列的 2n个座位上合影,同一对新人彼此挨着。由于进场时各对新人并未按序入座,请计算最少交换座位的次数,以便使每对新人均可并肩坐在一起。一次交换可选择任意两人,让他们互换座位。
全部新人的序号可用 0 到 2n-1 的整数表示,第一对是 (0, 1),第二对是 (2, 3),以此类推,最后一对是 (2n-2, 2n-1)。
row[i]指最初坐在第 i 个座位上的新人编号,i是从0到(2n-1)的一个升序全排列,row不存在重复值。

输入描述:

输入共有2行,第一行为n,即共有多少对新人(2≤n≤100000 ),第二行为row,即2n个座位上的初始新人编号。
输出描述:
输出最少交换座位的次数。

示例1

输入

2
0 2 1 3
输出
1
说明
我们只需要交换1和2的位置即可

示例2

输入

2
3 2 0 1
输出
0
说明
无需交换座位,所有的新人都已经并肩坐在一起

思路:

1、为了找到所属的另一半,不能每次都进行遍历查找。因此,需要另一个数组arr[],存储每个人所在row[]中的位置。

2、以row=[0,2,1,3]为例,0想要找到另一半1,先找到1所在的位置,为arr[1]=2。之后,0为了和1坐在一起,0抢占3的位置(为什么不是抢占2的位置呢)。没有座位的3,自然是又进行寻找另一半2的位置的过程。

3、按照步骤2的方法,如果记录抢位置次数作为交换次数的话,会比实际交换次数多1。

4、怎么结束步骤2的循环呢,0原本所在的row[0]的位置被抢占后,循环就结束。

5、如果row=[0,2,1,3,4,6,5,7],只从0找的话,后面的4、6、5、7无法凑成一对,所以需要依次判断row[2i]和row[2i+1]是否是情侣,如果不是,则进行步骤2。

6、最后代码如下:

#include <iostream>
#include <vector>

using namespace std;

int minSwapsCouples(int n, vector<int>& row) {
	int *a= new int[2 * n];//存储每个人所在row[]的位置
	int len = n * 2;
	for (int i = 0; i<len; i++)
		a[row[i]] = i;
	int sum = 0;//交换次数
	int i = 0;
	while (i<len)
	{
		if (row[i] / 2 == row[i + 1] / 2) { i += 2; continue; }//如果相邻座位是情侣,则继续
		else//如果不是情侣
		{
			int n = row[i], m, c, index;//m是n要找的情侣,index为m的在row[]的位置
			do
			{
				if (n % 2) m = n - 1;
				else m = n + 1;
				index = a[m];
				if (index % 2) index--;
				else index++;

				c = row[index];//坐着的人走开
				row[index] = n;//情侣坐成一对
				n = c;//走开的人继续找另一半
				sum++;
			} while (index != i);//经过几次循环后,初始的位置被占领了,循环结束  
			sum--;
		}
	}

	return sum;
}

int main()
{
	int n = -1;
	cin >> n;
	vector<int> row;
	for (int i = 0; i < 2 * n; i++)
	{
		int temp = -1;
		cin >> temp;
		row.push_back(temp);
	}
	int result = minSwapsCouples(n, row);
	cout << result << endl;
	return 0;
}

参考:https://blog.csdn.net/ZRXSLYG/article/details/80461203

原文地址:https://www.cnblogs.com/whiteBear/p/12801436.html