原题: http://codeforces.com/contest/1173/problem/F
题意:
网格 ,n个人从左往右 ,n个人从上往下 ,你可以放多对传送门,来改变这些人的运动轨迹。
要满足左边第 个人走到 ,右边第 个人走到 ,其中 不会重复, 也是。
解析:
5
3 1 5 4 2
4 2 1 3 5
一个一个来,以上面的案例为例。左边第二个人要走到第一行,就放一个
,上面第三个人走到第一列,放
。
接下来是左边5走到2,上面2走到2。
为了满足上面的两个,我们在第一行和第一列不会放了。所以从第二行和第二列开始。
此时发现,你需要维护一个并查集,表示由之前的传送门的影响,还没有满足的点的动向。
代码:
#include<bits/stdc++.h>
using namespace std;
#define pill pair<int,int>
const int maxn=1009;
int a[maxn],b[maxn];
int pos[2][maxn];
vector<pill>V;
int fin(int id,int a){
return pos[id][a]==a?a:pos[id][pos[id][a]]=fin(id,pos[id][a]);
}
int main(){
int n;scanf("%d",&n);
for(int i=1;i<=n;i++)pos[0][i]=pos[1][i]=i;
for(int i=1,j;i<=n;i++)scanf("%d",&j),a[j]=i;
for(int i=1,j;i<=n;i++)scanf("%d",&j),b[j]=i;
for(int i=1;i<=n;i++){
int h=fin(0,a[i]),c=fin(1,b[i]);
if(h==i&&c==i){
continue;
}
V.push_back({h,i}),V.push_back({i,c});
pos[0][i]=h;
pos[1][i]=c;
}
printf("%d\n",(int)V.size()/2);
for(int i=0;i<V.size();i+=2){
printf("%d %d %d %d\n",V[i].first,V[i].second,V[i+1].first,V[i+1].second);
}
}