[NOIP2005] 提高组 洛谷P1053 篝火晚会
题目描述
佳佳刚进高中,在军训的时候,由于佳佳吃苦耐劳,很快得到了教官的赏识,成为了“小教官”。在军训结束的那天晚上,佳佳被命令组织同学们进行篝火晚会。一共有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。
输入输出样例
4 3 4 4 3 1 2 1 2
2
说明
对于30%的数据,n <= 1000;
对于全部的数据,n <= 50000。
2005提高组第三题
在新的环中,如果a和b的相对位置没有变(即a相对于原位置左移了x个位置,b也相对于原位置左移了x个位置,向右同理),那么可以考虑:如果不移动两人,只移动其他人,最优解是多少?
显然,如果在移动时,相对移动了x位的人最多,那么这种情况下,等同于需要移动的人越少。
需要移动的人数=总人数-不需要移动的人数。 (题中佳佳要求别人交换的顺序可以任意指定,所以在可行的情况下,让m个人归位只需要m代价)
具体处理方法见代码
1 /*by SilverN*/ 2 #include<algorithm> 3 #include<iostream> 4 #include<cstring> 5 #include<cstdio> 6 #include<cmath> 7 #include<vector> 8 using namespace std; 9 const int mxn=50010; 10 int read(){ 11 int x=0,f=1;char ch=getchar(); 12 while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();} 13 while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();} 14 return x*f; 15 } 16 int w[mxn][2]; 17 int c1[mxn],c2[mxn],r[mxn]; 18 int vis[mxn]; 19 int n; 20 int main(){ 21 n=read(); 22 int i,j; 23 for(i=1;i<=n;i++) w[i][0]=read(),w[i][1]=read(); 24 r[1]=1;r[2]=w[1][0]; 25 vis[r[1]]=vis[r[2]]=1; 26 for(i=2;i<n;i++){ 27 if(r[i-1]==w[r[i]][0])r[i+1]=w[r[i]][1]; 28 else if(r[i-1]==w[r[i]][1])r[i+1]=w[r[i]][0]; 29 else{printf("-1\n");return 0;} 30 vis[r[i+1]]=1; 31 } 32 for(i=1;i<=n;i++)if(!vis[i]){ 33 printf("-1\n"); 34 return 0; 35 } 36 for(i=1;i<=n;i++){ 37 c1[(r[i]-i+n)%n]++;//正序 38 c2[(r[n-i+1]-i+n)%n]++;//逆序 39 //WA 1: n-i+1写在了c2的外面 40 } 41 int ans=0; 42 for(i=1;i<=n;i++){ 43 ans=max(ans,c1[i]); 44 ans=max(ans,c2[i]); 45 } 46 printf("%d\n",n-ans); 47 return 0; 48 }