bzoj1934: [Shoi2007]Vote 善意的投票

一定要想到是最小割。

虚拟源点S连支持者容量为1,反对者连虚拟汇点容量为1,支持者连反对者容量为1。

割俩面的点,一面是支持,一面是反对,冲突数就是割(哥。。雾)。

最小冲突数就是最小割。

#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 300 + 10;
const int maxm = 100000 + 10;
const int INF = 0x3f3f3f3f;

int g[maxn],v[maxm],next[maxm],f[maxm],eid=0;
int n,m,a[maxn],S,T;
int d[maxn],gap[maxn];

void addedge(int a,int b,int F) {
    v[eid]=b; next[eid]=g[a]; f[eid]=F; g[a]=eid++; 
    v[eid]=a; next[eid]=g[b]; f[eid]=0; g[b]=eid++;
}

int ISAP(int u,int flow) {
    if(u==T) return flow;
    int aug,cur=0,mindist=n;
    for(int i=g[u];~i;i=next[i]) 
    if(d[u]==d[v[i]]+1 && f[i]>0) {
        aug=ISAP(v[i],min(f[i],flow-cur));
        f[i]-=aug;
        f[i^1]+=aug;
        cur+=aug;
        if(cur==flow || d[S] == n) return cur;
    }
    
    if(cur==0) {
        if(!--gap[d[u]]) {
            d[S] = n;
            return cur;
        }
        for(int i=g[u];~i;i=next[i]) if(f[i]) mindist=min(mindist,d[v[i]]);
        ++gap[d[u]=mindist+1];         
    }    
    return cur;
}

void solve() {
    gap[0]=n;
    int res=0;
    while(d[S]<n) res+=ISAP(S,INF);
    printf("%d\n",res);
}

int main() {
    scanf("%d%d",&n,&m);
    S=n+1; T=n+2;
    memset(g,-1,sizeof(g));
    for(int i=1;i<=n;i++) {
        scanf("%d",&a[i]);
        if(a[i]==1) addedge(S,i,1);
        else addedge(i,T,1);
    }
    n=n+2;
    for(int i=1,u,v;i<=m;i++) {
        scanf("%d%d",&u,&v);
        if(a[u]!=a[v]) {
            if(a[u]==1) addedge(u,v,1);
            else addedge(v,u,1);
        }
    }
    solve();
    return 0;
}
posted @ 2016-04-25 20:54  invoid  阅读(158)  评论(0编辑  收藏  举报