BZOJ1539/POI2005 Double-row

由于数据保证有一组方案达到目标,那么相同高度的士兵个数不超过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;
}
展开阅读全文

没有更多推荐了,返回首页