bzoj 1934最小割

  比较显然的最小割的题,增加节点source,sink,对于所有选1的人我们可以(source,i,1),选0的人我们可以(i,sink,1),然后对于好朋友我们可以连接(i,j,1)(j,i,1),然后我们求最小割就好了,因为我们可以将节点分为两部分,表示0,1的选法,那么我们割一条与sink,source连的边表示这个人与自己的意愿不同,需要1的代价,如果两个人连边,这两个人不在同一集合,那么这两个人割掉连边需要1的代价。

/**************************************************************
    Problem: 1934
    User: BLADEVIL
    Language: C++
    Result: Accepted
    Time:20 ms
    Memory:3156 kb
****************************************************************/
 
//By BLADEVIL
#include <cstdio>
#include <cstring>
#include <algorithm>
#define maxm 100010
#define maxn 400
#define inf (~0U>>1)
 
using namespace std;
 
int n,m,source,sink,l,ans;
int last[maxn],other[maxm<<1],len[maxm<<1],pre[maxm<<1],flag[maxn];
int que[maxn],d[maxn];
 
void connect(int x,int y,int z) {
    pre[++l]=last[x];
    last[x]=l;
    other[l]=y;
    len[l]=z;
}
 
bool bfs() {
    memset(d,0,sizeof d);
    que[1]=source; d[source]=1; 
    int h=0,t=1;
    while (h<t) {
        int cur=que[++h];
        for (int p=last[cur];p;p=pre[p]) {
            if (d[other[p]]) continue;
            if (!len[p]) continue;
            d[other[p]]=d[cur]+1;
            que[++t]=other[p];
            if (other[p]==sink) return 1;
        }
    }
    return 0;
}
 
int dinic(int x,int flow) {
    if (x==sink) return flow;
    int rest=flow;
    for (int p=last[x];p;p=pre[p]) {
        if (!len[p]) continue;  
        if (d[other[p]]!=d[x]+1) continue;
        if (!rest) continue;
        int tmp=dinic(other[p],min(len[p],rest));
        if (!tmp) d[other[p]]=0;
        len[p]-=tmp; len[p^1]+=tmp;
        rest-=tmp;
    }
    return flow-rest;
}
 
 
int main() {
    scanf("%d%d",&n,&m); 
    source=n+2; sink=source+1; l=1;
    for (int i=1;i<=n;i++) {
        scanf("%d",&flag[i]);
        if (flag[i]) connect(source,i,1),connect(i,source,0); else
            connect(i,sink,1),connect(sink,i,0);
    }
    for (int i=1;i<=m;i++) {
        int x,y; scanf("%d%d",&x,&y);
        connect(x,y,1); connect(y,x,0);
        connect(y,x,1); connect(x,y,0);
    }
    while (bfs()) ans+=dinic(source,inf);
    printf("%d\n",ans);
    return 0;
}

 

posted on 2014-04-21 09:41  BLADEVIL  阅读(473)  评论(0编辑  收藏  举报