[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;
}
posted @ 2019-03-17 18:17  xryjr233  阅读(40)  评论(0编辑  收藏