这道题,我感觉最大的难点在于对题目的理解,不知道是我理解能力有问题还是出题人叙述有问题,我花了很长的时间弄清楚题意,下面,我们把无用的信息筛去,从题意方面重新理解这道题。
一共有n个同学,编号从1到n,初始状态这n个人按1,2,……,n的顺序坐成一个环,每个人都希望与自己相邻的人坐在一起,如何下令调整同学的次序,形成新的一个圈,是之符合同学们的意愿。可以下达这样的命令(b1,b2,b3......bm),这里的m的值由我们决定,每次命令的m的值可以不同,这个命令的作用是移动编号是b1,b2,…… bm -1,bm的这m个同学的位置。要求b1换到b2的位置上,b2换到b3的位置上,……,要求bm换到b1的位置上。
我第一次理解成下达的命令只能从移动从1开始到m的同学(实际上不就是这样吗?) 但正确的理解应该是b1可以代表任何编号的童鞋。
所以我们可以这样想,对于一个打乱的序列,我们总有一种命令,可以一次使之变成我们想要的顺序,只要我们这个命令上的编号顺序进行一些设计。
我们可以根据每个人的意愿,生成一个符合每个人要求的环,如果不能生成,就输出-1。
接下来问题就转化为初始序列转化成目标序列需要的最少步数问题了。网上的一些资料居然还用到了置换群的知识点,我是没想到这么高深的做法,只是按照自己的思路写就AC了。
相对位置,恩,明白了吧。
#include<cstdio>
#include<iostream>
#include<string.h>
using namespace std;
const int maxn=50050;
int n,b[maxn],a[maxn][2];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&a[i][1],&a[i][2]);
}
b[1]=1;
b[2]=a[1][1];
int t1=b[1],t2=b[2];
for(int i=3;i<=n;t1=t2,t2=b[i],i++)
{
if(a[t2][1]==t1)b[i]=a[t2][2];
else
if(a[t2][2]==t1)b[i]=a[t2][1];
else
{
printf("-1");
return 0;
}
}
if(b[n]!=a[1][2])
{
printf("-1");
return 0;
}
memset(a,0,sizeof(a)); //a数组之前的作用是记录第i个位同学喜欢相邻的人 现在a数组已经没用了,我们可以“废物利用”
int t=0;
for(int i=1;i<=n;i++) //统计顺时针、逆时针相对位置相同的最多的数
{
a[(b[i]-i+n)%n][1]++; // 顺时针,加上n是避免出现负数,因为是环,所以用%n来循环。
a[(b[i]+i)%n][2]++;
}
for(int i=1;i<=n;i++)
{
if(a[i][1]>t)t=a[i][1];
if(a[i][2]>t)t=a[i][2];
}
printf("%d",n-t);
return 0;
}