额,我的是有多久没写网络流了 。。。。手生了
以前对于最小割的理解局限于最大流的演变上,我觉得这道题是一个很好的例子。我们将同意的和s连边,边权为一,将不同意的和t连边边权为1,朋友之间连边,边权还是一,这样一来,点与点之间就建立了联系,比如现在我要让一个原本统一的人不同意,在我们建立的图上面就相当于划掉他和他原来的点之间的连线,而割掉这一条边以后对于答案的贡献就是1,或者说让一个朋友和另外一个朋友产生矛盾,也只需要划去两个朋友之间的连线,同样的,当我们找到一条最小割以后将图 分成了s和t集合而这两个集合之间一定不会有任意两个人之间产生矛盾。因此,问题转变成了最小割问题
本人觉得因该是对于最小割更为本质的应用吧
#include<cstdio>
#include<cstring>
#include<iostream>
#define maxn 310
using namespace std;
int n,s,t,head[maxn],tot,m,d[maxn],last[maxn],vd[maxn];
struct edge{
int v,w,next;
}e[maxn*maxn*2];
void adde(int a,int b,int c){e[tot].v=b,e[tot].w=c,e[tot].next=head[a];head[a]=tot++;}
int dfs(int u,int flow){
if(u==t)return flow;
int res=0,temp=0;
for(int i=last[u];i!=-1;i=e[i].next )if(d[u]==d[e[i].v]+1&&e[i].w>0){
last[u]=i;
temp=dfs(e[i].v,min(e[i].w,flow-res));//我擦 一开始写成了flow-e[i].w找了好久
res+=temp,e[i].w-=temp,e[i^1].w+=temp;
if(res==flow)return res;
}
if(d[s]>=t)return res;
vd[d[u]]--;if(vd[d[u]]==0)d[s]=t;
d[u]++;vd[d[u]]++;
last[u]=head[u];
return res;
}
void sap(){
int ans=0;
for(int i=0;i<=t;i++)last[i]=head[i];
while(d[s]<t){
ans+=dfs(s,1e9);
}
printf("%d",ans);
}
int main(){
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&m);
s=0,t=n+1;
for(int x,i=1;i<=n;i++){
scanf("%d",&x);
x ? (adde(s,i,1),adde(i,s,0)) : (adde(i,t,1),adde(t,i,0));
}
for(int a,b,i=1;i<=m;i++){
scanf("%d%d",&a,&b);
adde(a,b,1),adde(b,a,0);
adde(b,a,1),adde(a,b,0);
}
sap();
return 0;
}