篝火晚会
题目描述
佳佳刚进高中,在军训的时候,由于佳佳吃苦耐劳,很快得到了教官的赏识,成为了“小教官”。在军训结束的那天晚上,佳佳被命令组织同学们进行篝火晚 会。一共有n个同学,编号从1到n。一开始,同学们按照1,2,……,n的顺序坐成一圈,而实际上每个人都有两个最希望相邻的同学。如何下命令调整同学的 次序,形成新的一个圈,使之符合同学们的意愿,成为摆在佳佳面前的一大难题。
佳佳可向同学们下达命令,每一个命令的形式如下:
(b1, b2,... bm -1, bm)
这里m的值是由佳佳决定的,每次命令m的值都可以不同。这个命令的作用是移动编号是b1,b2,…… bm的这m个同学的位置。要求b1换到b2的位置上,b2换到b3的位置上,……,要求bm换到b1的位置上。执行每个命令都需要一些代价。我们假定如果 一个命令要移动m个人的位置,那么这个命令的代价就是m。我们需要佳佳用最少的总代价实现同学们的意愿,你能帮助佳佳吗?
输入输出格式
输入格式:
输入文件fire.in的第一行是一个整数n(3 <= n <= 50000),表示一共有n个同学。其后n行每行包括两个不同的正整数,以一个空格隔开,分别表示编号是1的同学最希望相邻的两个同学的编号,编号是2的 同学最希望相邻的两个同学的编号,……,编号是n的同学最希望相邻的两个同学的编号。
输出格式:
输出文件fire.out包括一行,这一行只包含一个整数,为最小的总代价。如果无论怎么调整都不能符合每个同学的愿望,则输出-1。
输入输出样例
说明
对于30%的数据,n <= 1000;
对于全部的数据,n <= 50000。
仔细观察发现,所有可能的情况都是由其中一种情况进行环移或翻转得到的,
比如样例有一种情况为:1 4 2 3
其余情况为:
3 1 4 2
2 3 1 4
4 2 3 1
3 2 4 1
1 3 2 4
4 1 3 2
2 4 1 3
(观察一下)
代价也就是与开始不相等的数的个数
比如要排成1 4 2 3
原序列1 2 3 4
只有1不用移,4 2 3都不在目标序列上,因此代价为3
因为 比如遇到一个不应该放在原来的位置上,
则把它放到目标位置上,
但又把另一个元素挤了出来,
将挤出来的元素放到目标位置上,
又会有元素被挤出来,
继续进行相同的操作.……
直到所有元素(人)都安排好(心满意足)了。
再计算代价,就是上述结论。
但是,环移操作很费时,n^2,怎么办?
当然不能直接移,可以记f[i]为有f[i]个元素要进行i次环移操作才能移到自己的位置上
求f[i]的最大值就行了
再翻转做一次就行了
判断也很好判断
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 int cnt,a[50001],n,l[50001],r[50001],ans1[50001],ans2[50001],ans; 7 int main() 8 {int i,j; 9 cin>>n; 10 for (i=1;i<=n;i++) 11 scanf("%d%d",&l[i],&r[i]); 12 a[1]=1; 13 for (i=1;i<=n;i++) 14 if (r[l[i]]!=i&&l[l[i]]!=i||l[r[i]]!=i&&r[r[i]]!=i) 15 { 16 cout<<-1; 17 return 0; 18 } 19 a[2]=l[1]; 20 for (i=2;i<n;i++) 21 { 22 if (r[a[i]]==a[i-1]) a[i+1]=l[a[i]]; 23 else a[i+1]=r[a[i]]; 24 } 25 for (i=1;i<=n;i++) 26 { 27 ans1[(a[i]-i+n)%n]++; 28 ans2[(a[i]+i-1)%n]++; 29 } 30 for (i=0;i<n;i++) 31 ans=max(ans,max(ans1[i],ans2[i])); 32 cout<<n-ans; 33 }