[2019.3.5]BZOJ1934 [Shoi2007]Vote 善意的投票
一看数据范围题意猜测是网络流。
于是开始建模。
我们建立源点\(S\)和汇点\(T\),将\(S\)向想要睡觉的小朋友连容量为1的边,将不想睡觉的小朋友向\(T\),连容量为1的边,朋友之间连流量为1的双向边。
那么我们需要使图被分为两个互不连通的集合,一个和\(S\)连通,表示最终投了睡觉的小朋友;另一个和\(T\)连通,表示最终投了不睡的小朋友。
那么最小冲突次数就是最小割了。
为什么呢?
可以把一条边看成一次可能的冲突,割断了就是接受了一次冲突,让一这对朋友冲突之后,两个小朋友都可以不用考虑这个朋友关系,这个限制就不存在了,也就是边被割断了。
code:
#include<bits/stdc++.h>
#define REV(x) (x&1?x+1:x-1)
#define S 0
#define T n+1
using namespace std;
struct edge{
int t,f,nxt;
}e[200010];
int n,m,u,v,t,cnt,be[310],dep[310],vis[310];
queue<int>q;
void add(int x,int y,int f){
e[++cnt].t=y,e[cnt].f=f,e[cnt].nxt=be[x],be[x]=cnt;
}
void Add(int x,int y,int f){
add(x,y,f),add(y,x,0);
}
bool bfs(){
for(int i=1;i<=T;++i)dep[i]=0;
dep[S]=1,q.push(S);
while(!q.empty()){
t=q.front(),q.pop();
for(int i=be[t];i;i=e[i].nxt)!dep[e[i].t]&&e[i].f?q.push(e[i].t),dep[e[i].t]=dep[t]+1:0;
}
return dep[T];
}
int dfs(int x,int nf){
if(x==T)return nf;
vis[x]=1;
int tf,uf=0;
for(int i=be[x];i&&nf>uf;i=e[i].nxt)!vis[e[i].t]&&dep[e[i].t]==dep[x]+1&&e[i].f?tf=dfs(e[i].t,min(e[i].f,nf-uf)),uf+=tf,e[i].f-=tf,e[REV(i)].f+=tf:0;
return uf;
}
int Dinic(){
int ans=0;
while(bfs())ans+=dfs(S,1e9);
return ans;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)scanf("%d",&t),t?Add(S,i,1):Add(i,T,1);
for(int i=1;i<=m;++i)scanf("%d%d",&u,&v),Add(u,v,1),Add(v,u,1);
printf("%d",Dinic());
return 0;
}