[POI2005]DWU-Double-row

这里写图片描述
题意:有长度为 n n 的二元组 (ai,bi)。可交换 (ai,bi) ( a i , b i ) 。使得任意 ai!=aj a i ! = a j bi!=bj b i ! = b j 的最少交换次数。
对于两个二元组如果他们有相同权值的元素那么会有两种关系:
1. 1. 必须换其中任意 1 1 个。
2. 若交换 两个必须都要换。

两种点之间有冲突关系,有共生关系。有一道很久前做的题…封锁阳光大学。
考虑把每个位置看成一个点,将图进行二分染色。共生关系的点颜色必须相同,冲突关系的点颜色必须不同。对于每个连通块求出其中数量少的点即可。

#include<bits/stdc++.h>
using namespace std;

const int MAXN=5e5+5;

struct edge{
    int to,next,w;
}e[MAXN<<1];

int head[MAXN],cnt=0;
inline void add(int u,int v,int w){
    e[++cnt]=(edge){v,head[u],w},head[u]=cnt;
    e[++cnt]=(edge){u,head[v],w},head[v]=cnt;
}

int n,limit=0;
bool vis[MAXN];
int color[MAXN],c[2];
vector<int>up[MAXN],down[MAXN];

void dfs(int u){
    for(int i=head[u];i;i=e[i].next){
        int v=e[i].to,w=e[i].w;
        if(!vis[v]){
            vis[v]=1;
            if(w==1){
                color[v]=color[u]^1;
                c[color[v]]++;
                dfs(v);
            }
            else {
                color[v]=color[u];
                c[color[u]]++;
                dfs(v);
            }
        }
    }
}

int main(){
    memset(vis,0,sizeof(vis));
    memset(color,-1,sizeof(color));
    c[0]=c[1]=0;
    scanf("%d",&n); 
    for(int i=1;i<=n;i++){
        int tmp;
        scanf("%d",&tmp);
        up[tmp].push_back(i);
        limit=max(limit,tmp);
    }
    for(int i=1;i<=n;i++){
        int tmp;
        scanf("%d",&tmp);
        down[tmp].push_back(i);
        limit=max(limit,tmp);
    }
    for(int i=1;i<=limit;i++){
        if(up[i].size()==2)
            add(up[i][0],up[i][1],1);
        else if(down[i].size()==2)
            add(down[i][0],down[i][1],1);
        else if(down[i].size()==1&&up[i].size()==1)
            add(down[i][0],up[i][0],0);
    }
    int ans=0;
    for(int i=1;i<=limit;i++)if(!vis[i]){
        c[0]++,color[i]=0;
        vis[i]=1;
        dfs(i);
        ans+=min(c[0],c[1]);
        c[0]=c[1]=0;
    }
    //cout<<c[0]<<" "<<c[1]<<endl;
    printf("%d\n",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值