由于数据保证有一组方案达到目标,那么相同高度的士兵个数不超过2. 每列交换的次数最多是1,多次交换是无意义的.
那么假如身高相同的两个士兵在同一行中,它们所在的列数a,b中一定有一列要进行交换,且只有一列.
那么假如身高相同的两个士兵在不同行中,它们所在的列数a,b中要么都进行交换,或者都不进行交换.
有了列与列之间的关系就可以建对以上两类情况分别建边,进行01染色,将边分为两个集合,每次选择较小集合进行操作.
#include<cstdio>
#include<cstring>
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int M=5e4+5;
int a[M<<1],b[M<<1],f[M],n,mark[M],cnt[2];
struct node{
int to,v;///v=0,相同,v=1不能相同
};
inline void rd(int &res){
res=0;char c;
while(c=getchar(),c<48);
do res=(res<<1)+(res<<3)+(c^48);
while(c=getchar(),c>=48);
}
vector<node>e[M];
void dfs(int x){
cnt[mark[x]]++;
for(int i=0;i<e[x].size();i++){
int y=e[x][i].to,v=e[x][i].v;
if(~mark[y])continue;
mark[y]=v^mark[x];
dfs(y);
}
}
int main(){
int i,j,k,ans=0;
memset(mark,-1,sizeof(mark));
scanf("%d",&n);
for(i=1;i<=n;i++){
rd(k);
if(a[k]){
e[i].push_back((node){a[k],1});
e[a[k]].push_back((node){i,1});
f[i]=f[a[k]]=1;
}
a[k]=i;
}
for(i=1;i<=n;i++){
rd(k);
if(a[k]){
e[a[k]].push_back((node){i,0});//必须相同
e[i].push_back((node){a[k],0});
}
else if(b[k]){
e[i].push_back((node){b[k],1});
e[b[k]].push_back((node){i,1});
f[i]=f[b[k]]=1;
}
b[k]=i;
}
for(i=1;i<=n;i++){
if(f[i]&&mark[i]==-1){
cnt[0]=0,cnt[1]=0;
mark[i]=1;
dfs(i);
ans+=min(cnt[0],cnt[1]);
}
}
printf("%d\n",ans);
return 0;
}