第 45 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(昆明) J(EX构造+环的性质) 铜牌题
- 代码参考于三个顶俩,码量相对其余百来行较少。为什么至多只会操作俩次别的博客讲的很好,我就不献丑了。
v
p
vp
vp三题,这道题没出,打铁。大致做法就是,如果两个能直接交换则直接交换,如果不能那么则可以通过不断的交换留给下一次操作一个可以一次完成的局面。
例: 641532 (6要去2所在的位置,2要与1交换)
?
\Rightarrow
? 642531 (2要去4所在位置,4要与3交换)
?
\Rightarrow
? 63254 (得到下一次一定能完成的局面)。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
int x[N],y[N];
int cnt;
bool ok[N];
int a[N];
int b[N];
void exchange(int xx,int yy){
a[++cnt]=xx;
b[cnt]=yy;
swap(x[xx],x[yy]);
y[x[xx]]=xx;
y[x[yy]]=yy;
}
void dfs(int idx){
if(x[x[idx]]!=idx){
int j=x[idx];
int k=y[idx];
exchange(j,k);
ok[j]=ok[k]=true;
dfs(k);
}
}
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++)cin>>x[i],y[x[i]]=i;
int k=0;
for(int i=1;i<=n;i++){
if(x[i]!=i)k=max(1,k);
if(x[x[i]]!=i)k=2;
}
cout<<k<<endl;
while(1){
cnt=0;
bool st = true;
for(int i=1;i<=n;i++){
if(x[i]!=i)st=false;
}
if(st)break;
memset(ok,false,sizeof ok);
for(int i=1;i<=n;i++){
if(!ok[i]){
if(x[i]==i){
ok[i]=true;
continue;
}
else if(x[x[i]]==i&&!ok[x[i]]){
ok[i]=ok[x[i]]=true;
exchange(i,x[i]);
}
else if(x[x[i]]!=i){
ok[i]=true;
dfs(i);
}
}
}
cout<<cnt<<' ';
for(int i=1;i<=cnt;i++)cout<<a[i]<<' '<<b[i]<<' ';
cout<<endl;
}
return 0;
}
|