JZOJ4675. 【NOIP2016提高A组模拟7.21】Double-row

来源:互联网 发布:ubuntu修改ip地址命令 编辑:程序博客网 时间:2024/05/16 14:52

Description

科学家温斯顿在一张超长的白纸上写下了两行数,每一行数有N个。
但他写完后觉得看起来有点不和谐。他希望重新编排,使得每一行数中没有相同的数。
他每次可以调换同一列的两个数。
请帮他找到操作次数最少的方案。

分析

很显然,同一个数最多出现三次,不然的话那就一定无解。
现在,我们来考虑某一列是否交换,
分以下几种情况:
1、第x列和第y列在同一行的数相同,显然要不x列交换,要不y列交换。那我们就在x和y之间连一条边权为1的边,表示他们之间一定要有一列交换。
2、第x列和第y列在不同一行的数相同,那么如果第x列交换,就会与第y列冲突。所以这种情况要么不交换,要么都交换。那我们就在x和y之间连一条边权为0的边,表示他们之间要么不交换,要么都交换。
对于每一个联通块,我们就假定一列交换,
然后根据连边情况,确定其他列的情况,
最后如果发现不交换比交换的次数少,那就将不交换的变为交换,交换的变为不交换。

code

#include <cstdio>#include <algorithm>#include <cstring>#include <string.h>#include <cmath>#include <math.h>#define N 50003using namespace std;int a[N],b[N],s[2*N][2],t[2*N][2],f[N];int tot,to[2*N],v[2*N],next[2*N],last[N];int n,ans,sum[2];bool bz[N];char ch;void read(int &n){    n=0;    ch=getchar();    while((ch<'0' || ch>'9') && ch!='-')ch=getchar();    int w=1;    if(ch=='-')w=-1,ch=getchar();    while('0'<=ch && ch<='9')n=n*10+ch-'0',ch=getchar();    n*=w;}void ins(int x,int y,int z){    next[++tot]=last[x];    to[tot]=y;    v[tot]=z;    last[x]=tot;}void dg(int x){    sum[f[x]]++;    bz[x]=0;    for(int i=last[x];i;i=next[i])        if(bz[to[i]])        {            if(v[i]==1)f[to[i]]=1-f[x];else f[to[i]]=f[x];            dg(to[i]);        } }int main(){    read(n);    for(int i=1;i<=n;i++)    {        read(a[i]);        if(s[a[i]][0])ins(s[a[i]][0],i,1),ins(i,s[a[i]][0],1),s[a[i]][1]=i;else s[a[i]][0]=i;    }    for(int i=1;i<=n;i++)    {        read(b[i]);        if(t[b[i]][0])ins(t[b[i]][0],i,1),ins(i,t[b[i]][0],1),t[b[i]][1]=i;else t[b[i]][0]=i;        if(s[b[i]][0])ins(s[b[i]][0],i,0),ins(i,s[b[i]][0],0);        if(s[b[i]][1])ins(s[b[i]][1],i,0),ins(i,s[b[i]][1],0);    }    memset(bz,1,sizeof(bz));    ans=0;    for(int i=1;i<=n;i++)        if(bz[i])sum[0]=sum[1]=0,dg(i),            ans+=min(sum[0],sum[1]);    printf("%d",ans);} 
原创粉丝点击