标签:
【问题描述】
佳佳刚进高中,在军训的时候,由于佳佳吃苦耐劳,很快得到了教官的赏识,成为了“小教官”。在军训结束的那天晚上,佳佳被命令组织同学们进行篝火晚会。一共有n个同学,编号从1到n。一开始,同学们按照1,2,……,n的顺序坐成一圈,而实际上每个人都有两个最希望相邻的同学。如何下命令调整同学的次序,形成新的一个圈,使之符合同学们的意愿,成为摆在佳佳面前的一大难题。
佳佳可向同学们下达命令,每一个命令的形式如下:
(b1, b2,... bm -1, bm)
这里m的值是由佳佳决定的,每次命令m的值都可以不同。这个命令的作用是移动编号是b1,b2,…… bm -1,bm的这m个同学的位置。要求b1换到b2的位置上,b2换到b3的位置上,……,要求bm换到b1的位置上。
执行每个命令都需要一些代价。我们假定如果一个命令要移动m个人的位置,那么这个命令的代价就是m。我们需要佳佳用最少的总代价实现同学们的意愿,你能帮助佳佳吗?
【输入文件】
输入文件fire.in的第一行是一个整数n(3 <= n <= 50000),表示一共有n个同学。其后n行每行包括两个不同的正整数,以一个空格隔开,分别表示编号是1的同学最希望相邻的两个同学的编号,编号是2的同学最希望相邻的两个同学的编号,……,编号是n的同学最希望相邻的两个同学的编号。
【输出文件】
输出文件fire.out包括一行,这一行只包含一个整数,为最小的总代价。如果无论怎么调整都不能符合每个同学的愿望,则输出-1。
【样例输入】
4
3 4
4 3
1 2
1 2
【样例输出】
2
【数据规模】
对于30%的数据,n <= 1000;
对于全部的数据,n <= 50000。
【思路】
假设起始状态为1...n。首先以第一个孩子为起点,模拟实现一个环的目标状态。此时如果建环过程中出现矛盾,直接输出-1;否则,一定可以通过若干次操作移动到目标状态。
由于是环,起点位置可以改变,而且可以正序倒序两种方式。有以下几个结论:
(1)两个数,如果它们和起始状态的差加上n再mod n的结果一样,说明它们共同移动某步,能移动到目标状态。看下面这个例子:
起始状态:1 2 3 4 5
目标状态:1 5 3 2 4
差值: 0 3 0 -2 -1
我们可以发现,对于5和2,(3%5=3),((-2+5)%5=3)相等。而这两个数向右移动两位,都可以到达目标状态。
(2)每次移动一个价值,一定能使得一个数到达自己的目标状态。也就是说,有几个数与目标状态不对应,就需要消耗多少价值。
由此我们可以明白:
把差值(加n %n后)相同个数的最大值max求出来,然后把这几个数假设就在目标状态,那么移动需要的价值为n-max。因为环可以正反,正反各来一次即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 const int MAXN= 50000+500; 8 int n; 9 int want[MAXN][2]; 10 int q[MAXN]; 11 12 void init() 13 { 14 scanf("%d",&n); 15 for (int i=0;i<n;i++) 16 { 17 scanf("%d%d",&want[i][0],&want[i][1]); 18 want[i][0]--; 19 want[i][1]--; 20 } 21 } 22 23 int canmake() 24 { 25 q[0]=0; 26 q[1]=want[0][0]; 27 for (int i=1;i<n-1;i++) 28 { 29 if (q[i-1]!=want[q[i]][0]) q[i+1]=want[q[i]][0]; 30 else if (q[i-1]!=want[q[i]][1]) q[i+1]=want[q[i]][1]; 31 else return 0; 32 } 33 if (want[q[n-1]][0]!=0 && want[q[n-1]][1]!=0) return 0; 34 for (int i=0;i<n;i++) cout<<q[i]<<endl; 35 return 1; 36 } 37 38 void submain() 39 { 40 int ans=0; 41 int appear[MAXN]; 42 int appear2[MAXN]; 43 memset(appear,0,sizeof(appear)); 44 memset(appear2,0,sizeof(appear2)); 45 for (int i=0;i<n;i++) 46 { 47 appear[(q[i]-i+n)%n]++; 48 appear2[(q[i]+i-1)%n]++; 49 if (appear[(q[i]-i+n)%n]>ans) ans=appear[(q[i]-i+n)%n]; 50 if (appear2[(q[i]+i-1)%n]>ans) ans=appear2[(q[i]+i-1)%n]; 51 } 52 cout<<n-ans<<endl; 53 } 54 55 int main() 56 { 57 //freopen("fire9.in","r",stdin); 58 //freopen("fire9.out","w",stdout); 59 init(); 60 if (canmake()) submain(); 61 else cout<<-1<<endl; 62 system("pause"); 63 return 0; 64 }
标签:
原文地址:http://www.cnblogs.com/iiyiyi/p/4856697.html