交换座位
题目描述
在一场集体婚礼上,有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;
}