BZOJ 1934 Vote 善意的投票(最小割+二分图)
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1934
题目大意:
幼儿园里有n个小朋友打算通过投票来决定睡不睡午觉。对他们来说,这个问题并不是很重要,于是他们决定发扬谦让精神。虽然每个人都有自己的主见,但是为了照顾一下自己朋友的想法,他们也可以投和自己本来意愿相反的票。我们定义一次投票的冲突数为好朋友之间发生冲突的总数加上和所有和自己本来意愿发生冲突的人数。 我们的问题就是,每位小朋友应该怎样投票,才能使冲突数最小?
解题思路:
构建源S,汇T
然后S->一开始投同意的xpy,一开始投反对票的xpy ->T
流量均为1
然后对于一个朋友关系(a,b) 添加双向边,流量依然为1
最后割即为冲突数。
(1) 冲突数不大于 n:
很显然,哪怕所有xpy之间都存在朋友关系,xpy可以通过改变(或不改变)原先的决定到达全“同意”或全“否定”,那么朋友之间的冲突数为0,而未被自己先前决定的冲突数不大于n
(2) “同意”集合和“否定”集合之间的边全部是朋友关系
(3) 冲突是同意与不同意之间的割
按我的理解说一下,这样建图完毕后,为什么求的是S->T的最小割。
一、如果割掉S->i的边那说明这个小朋友违背了自己原本想睡觉的意愿,割掉i->T也是同理,冲突数+1.
二、如果割掉i->j即同意与不同意两个集合之间的边,则说明两好友意见不同,冲突数+1。
每个小朋友都要选择同意或者不同意,如果存在S->T的路径,说明有小朋友没有表态,这是不合法的,所以就是求S->T的最小割。
代码
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 #include<queue> 7 #include<vector> 8 #define LL long long 9 #define pii pair<int,int> 10 #define pll pair<long long,long long> 11 #define rep(i,a,b) for(int i=a;i<=b;i++) 12 #define per(i,a,b) for(int i=a;i>=b;i--) 13 #define FAST_IO ios::sync_with_stdio(false);cin.tie(0); 14 #define bug cout<<"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"<<endl; 15 #define bugc(_) cout << (#_) << " = " << (_) << endl; 16 using namespace std; 17 const int N=1e6+5; 18 const int M=1e6+5; 19 const int INF=0x3f3f3f3f; 20 21 struct node{ 22 int to,next,flow; 23 }edge[M*2]; 24 25 int cnt,st,en; 26 int head[N],dep[N]; 27 28 void init(){ 29 cnt=2; 30 memset(head,0,sizeof(head)); 31 } 32 33 void link(int u,int v,int flow){ 34 edge[cnt]=node{v,head[u],flow}; 35 head[u]=cnt++; 36 edge[cnt]=node{u,head[v],0}; 37 head[v]=cnt++; 38 } 39 40 int bfs(){ 41 memset(dep,0,sizeof(dep)); 42 dep[st]=1; 43 queue<int>q; 44 q.push(st); 45 while(!q.empty()){ 46 int u=q.front(); 47 q.pop(); 48 for(int i=head[u];i;i=edge[i].next){ 49 node t=edge[i]; 50 if(t.flow&&!dep[t.to]){ 51 dep[t.to]=dep[u]+1; 52 q.push(t.to); 53 } 54 } 55 } 56 return dep[en]; 57 } 58 59 int dfs(int u,int fl){ 60 if(u==en) return fl; 61 int tmp=0; 62 for(int i=head[u];i&&fl;i=edge[i].next){ 63 node &t=edge[i]; 64 if(t.flow&&dep[t.to]==dep[u]+1){ 65 int x=dfs(t.to,min(t.flow,fl)); 66 if(x>0){ 67 t.flow-=x; 68 edge[i^1].flow+=x; 69 tmp+=x; 70 fl-=x; 71 } 72 } 73 } 74 if(!tmp) dep[u]=-2; 75 return tmp; 76 } 77 78 int dinic(){ 79 int ans=0; 80 while(bfs()){ 81 while(int d=dfs(st,INF)){ 82 ans+=d; 83 } 84 } 85 return ans; 86 } 87 88 int main(){ 89 int n,m; 90 while(~scanf("%d%d",&n,&m)){ 91 init(); 92 st=0,en=n+1; 93 for(int i=1;i<=n;i++){ 94 int x; 95 scanf("%d",&x); 96 if(x==1) 97 link(st,i,1); 98 else 99 link(i,en,1); 100 } 101 for(int i=1;i<=m;i++){ 102 int u,v; 103 scanf("%d%d",&u,&v); 104 link(u,v,1); 105 link(v,u,1); 106 } 107 int ans=dinic(); 108 printf("%d\n",ans); 109 } 110 return 0; 111 }