P1053 篝火晚会
题意
题目描述
现有 \(n\) 个人,编号为 \(1\) 到 \(n\)。一开始,他们按 \(1,2,\dots,n\) 的顺序排成一圈。然而,每个人都有其最希望相邻的两个人。
我们可以执行以下操作若干次,使得最后排列的顺序能满足每个人的要求:
- 给定一个序列 \((b_1,b_2,\cdots,b_{m-1},b_m)\),并让 \(b_1\) 换到 \(b_2\) 的位置上,\(b_2\) 换到 \(b_3\) 的位置上,……,\(b_{m-1}\) 换到 \(b_m\) 的位置上,\(b_m\) 换到 \(b_1\) 的位置上。这一操作的代价为 \(m\),并且每次操作的 \(m\) 可以不相等。
注意:移动的人不一定要连续。
若能通过若干次操作,使得最后的顺序能满足每个人的要求,则输出最小总代价;否则输出 \(-1\)。
输入格式
第一行一个正整数 \(n\)(\(3\le n\le5\times10^4\)),含义见题目描述。
之后的 \(n\) 行每行都包括两个正整数 \(A_i\) 和 \(B_i\)(\(1\le A_i,B_i\le n\) 且 \(A_i\neq B_i\)),表示编号为 \(i\) 的人最希望与之相邻的两个人的编号。
输出格式
见题目描述。
思路
首先,根据每个人的希望,我们可以先尝试构造出一条目标链,如果构造不出来,则可以直接输出 \(-1\)。
然后,我们将目标链与初始链对应的数作差(模 \(n\) 的意义下),那些结果为 \(0\) 的人的位置是不用变的,而剩下的人都需要调整。
接着我们便可以惊奇的发现,若需要调整的人数为 \(m\),则我们只需要 \(1\) 次代价为 \(m\) 的操作即可将他们调整好 (至于为什么则留给读者思考)。
当然由于环是可以旋转的,所以实际上我们不需要调整的人不一定就是作差后结果为 \(0\) 的人。那么,选择哪些人可以使我们操作的总代价最小呢?
为了使调整的人数最少,我们无需调整的人数就要最多。而实际上,只要我们采取合适的旋转方式,任何一个人都可以由需要调整,变为不需要调整。因此,我们只需统计在作差得到的结果中出现次数最多的数(即众数)出现了几次,而这就是无需调整的人数。
最后,由于最初的顺序是顺时针还是逆时针不确定,所以我们需要二者都跑一遍,最后得出结果。
例如,对于样例,模拟结果如下:
- 构造目标链:\(1,4,2,3\)。
- 构造初始链:\(1,2,3,4\)。
- 顺时针统计:\(0,2,3,3\)。
- 逆时针统计:\(1,1,0,2\)。
- 无需调整的人数:\(2\)。
- 最终结果:\(4-2=2\)。
因此输出结果为:
2
程序
#include<cstdlib>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cstdio>
#include<iostream>
#include<vector>
#include<map>
#include<cmath>
#include<iomanip>
#include<string>
#include<stack>
using namespace std;
long long T=1,mod;
#define ll long long
#define ull unsigned long long
#define LL 2e18
#define INT 1e9
#define INF 0x3f3f3f3f
#define MAX int(50000)
//#define DEBUG
//#define use_cin
//#define more_text
int n, //人数
expect_person[MAX+1][2]; //每个人希望相邻的两个人
int target_list[MAX+1], //目标链
initial_list[MAX+1], //初始链
plus_order[MAX+1], //顺时针,统计作差结果出现的次数
minus_order[MAX+1], //逆时针,统计作差结果出现的次数
ans; //记录无需调整的人数的最大值
void solve(int step){
scanf("%d",&n);
for(int i=1;i<=n;++i)scanf("%d%d",&expect_person[i][0],&expect_person[i][1]);//输入
target_list[1]=1;
target_list[2]=expect_person[1][1];
for(int i=2;i<=n-1;++i){
if(target_list[i-1]==expect_person[target_list[i]][0])
target_list[i+1]=expect_person[target_list[i]][1];
else if(target_list[i-1]==expect_person[target_list[i]][1])
target_list[i+1]=expect_person[target_list[i]][0];
else{
printf("-1"); //无法满足要求
return;
}
} //构造目标链
for(int i=1;i<=n;++i)initial_list[i]=i; //构造初始链
for(int i=1;i<=n;++i)
++plus_order[(target_list[i]-initial_list[i]+n)%n], //顺时针统计
++minus_order[(target_list[i]-initial_list[n-i+1]+n)%n]; //逆时针统计
for(int i=0;i<n;++i)
ans=max(ans,max(plus_order[i],minus_order[i])); //统计答案
printf("%d",n-ans); //输出
}
int main(){//模板,不用在意
#ifdef DEBUG
freopen("test.in","r",stdin);freopen("test.out","w",stdout);
#endif
#ifdef more_text
#ifdef use_cin
cin>>T;
#else
scanf("%lld",&T);
#endif
#endif
for(int i=0;i<T;++i)solve(i);
#ifdef DEBUG
fclose(stdin);fclose(stdout);
#endif
return 0;
}
/*
Input:
Output:
Outline:
*/

浙公网安备 33010602011771号