题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1934
思路:对于一个小朋友支持,将其与源s相连,否则与汇t相连,好朋友之间相连,容量均为1。
对于一个割C(S,T),若某一支持的小朋友被划到T,那么他与s之间的连边必定被割去,且与同在T的好用的边可以不属于割边,若在S,则他与划在T的好友的边必为割边,所以每个割都对应着一种冲突情况且等于冲突数,所以最小割即为答案。
代码:
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
#define MAXN 305
struct node {
int t,f;
node *next,*pair;
};
node *head[MAXN],*d[MAXN];
int gap[MAXN],h[MAXN];
int n,m;
int S,T;
void INSERT(int s,int t,int f){
node *p=new(node);
p->t=t;;
p->f=f;
p->next=head[s];
head[s]=p;
}
int ans=0;
int sap(int v,int flow){
if (v==T) return flow;
int rec=0;
for (node *p=d[v];p;p=p->next){
if (p->f&&h[v]==h[p->t]+1){
int ret=sap(p->t,min(flow-rec,p->f));
p->f-=ret;
p->pair->f+=ret;
d[v]=p;
if ((rec+=ret)==flow) return flow;
}
}
if (!(--gap[h[v]])) h[S]=T;
gap[++h[v]]++;
d[v]=head[v];
return rec;
}
int main(){
memset(head,0,sizeof(head));
scanf("%d%d",&n,&m);
S=n+1;
T=S+1;
for (int i=0;i++<n;){
int x;
scanf("%d",&x);
if (x){
INSERT(S,i,1);
INSERT(i,S,0);
head[S]->pair=head[i];
head[i]->pair=head[S];
} else {
INSERT(i,T,1);
INSERT(T,i,0);
head[i]->pair=head[T];
head[T]->pair=head[i];
}
}
while (m--){
int s,t;
scanf("%d%d",&s,&t);
INSERT(s,t,1);
INSERT(t,s,1);
head[s]->pair=head[t];
head[t]->pair=head[s];
}
memset(gap,0,sizeof(gap));
memset(h,0,sizeof(h));
for (int i=0;i++<T;){
d[i]=head[i];
}
gap[0]=T;
while (h[S]<T){
ans+=sap(S,0x7fffffff);
}
printf("%d\n",ans);
return 0;
}