【BZOJ1934】【codevs2341】善意的投票,二分图最小割

来源:互联网 发布:软件注册机 编辑:程序博客网 时间:2024/05/18 02:49

传送门1
传送门2
写在前面:看Yveh颓炉石,貌似只能打韩大的时候很爽?
思路:按01分成两份,s连1,0连t,好朋友间互相连接两次,容量都是1,每一个流量都是一次冲突,最小割最大流定理即可
注意:好朋友间一定要互相连,不是单向的连!
代码:

#include<bits/stdc++.h>#define inf 0x7fffffusing namespace std;int tot=1,n,m,s,t;int first[303],dis[303];bool a[303];struct edge{    int u,v,w,next;}e[200000];queue<int>q;void add(int x,int y,int z){e[++tot]=(edge){x,y,z,first[x]};first[x]=tot;}bool bfs(){    memset(dis,0,sizeof(dis));    dis[s]=1;    q.push(s);    while (!q.empty())    {        int k=q.front();        for (int i=first[k];i;i=e[i].next)            if (!dis[e[i].v]&&e[i].w)                q.push(e[i].v),dis[e[i].v]=dis[k]+1;        q.pop();    }    return dis[t];}int dfs(int x,int maxn){    if (x==t) return maxn;    int used=0;    for (int i=first[x];i;i=e[i].next)        if(dis[e[i].v]==dis[x]+1)        {            int k=dfs(e[i].v,min(maxn,e[i].w));            e[i].w-=k;e[i^1].w+=k;            used+=k;            if (used==maxn) return maxn;        }    if (!used) dis[x]=0;    return used;}main(){    scanf("%d%d",&n,&m);    int x,y;    t=n+1;    for (int i=1;i<=n;i++)    {        scanf("%d",a+i);        if (a[i]) add(s,i,1),add(i,s,0);        else add(i,t,1),add(t,i,0);    }    for (int i=1;i<=m;i++)    {        scanf("%d%d",&x,&y);        add(x,y,1),add(y,x,0),add(y,x,1),add(x,y,0);     }    int ans=0;    while (bfs()) ans+=dfs(s,inf);    printf("%d",ans);}
0 0