bzoj1934 [Shoi2007]Vote 善意的投票
幼儿园里有n个小朋友打算通过投票来决定睡不睡午觉。对他们来说,这个问题并不是很重要,于是他们决定发扬谦让精神。虽然每个人都有自己的主见,但是为了照顾一下自己朋友的想法,他们也可以投和自己本来意愿相反的票。我们定义一次投票的冲突数为好朋友之间发生冲突的总数加上和所有和自己本来意愿发生冲突的人数。 我们的问题就是,每位小朋友应该怎样投票,才能使冲突数最小?Input第一行只有两个整数n,m,保证有2≤n≤300,1≤m≤n(n-1)/2。其中n代表总人数,m代表好朋友的对数。文件第二行有n个整数,第i个整数代表第i个小朋友的意愿,当它为1时表示同意睡觉,当它为0时表示反对睡觉。接下来文件还有m行,每行有两个整数i,j。表示i,j是一对好朋友,我们保证任何两对i,j不会重复。Output只需要输出一个整数,即可能的最小冲突数。Sample Input
3 3 1 0 0 1 2 1 3 3 2
Sample Output
1
Hint
在第一个例子中,所有小朋友都投赞成票就能得到最优解
这是到网络流的例题吧。
题解:就是每个小朋友可以从投自己心仪的票,然后没有好朋友,这样就是互相不冲突的,
有冲突的话就是要么符合好朋友,要么就是符合自己的心仪投票,没有其他的方案了,
这样如果小朋友要符合好朋友,违背心向,则让其连向好朋友,表示他的意向变为好朋友的,
然后他就违背了自己的心愿,就是+1的结果,也或者是,将好朋友的变成了自己的票,然后去
一个最小的,就是最小割。使图没有冲突。
然后就是跑一次网络流。
1 #include<cstdio> 2 #include<algorithm> 3 #include<cmath> 4 #include<iostream> 5 #include<cstring> 6 using namespace std; 7 8 const int INF=1e8+8; 9 10 int n,m,S,T; 11 int cnt,head[507],next[101007],val[101007],rea[101007]; 12 int dis[507],p[507];//因为是宽搜,所以p的空间开节点个数 13 14 void add(int u,int v,int zhi) 15 { 16 cnt++; 17 next[cnt]=head[u]; 18 head[u]=cnt; 19 rea[cnt]=v; 20 val[cnt]=zhi; 21 } 22 bool bfs() 23 { 24 memset(dis,-1,sizeof(dis)); 25 dis[S]=0; 26 int hd=0,tl=1; 27 p[tl]=S; 28 while (hd<tl) 29 { 30 hd++; 31 int u=p[hd]; 32 for (int i=head[u];i!=-1;i=next[i]) 33 { 34 int v=rea[i],cost=val[i]; 35 if (dis[v]==-1&&cost>0)//如果当前阻塞流的流量为0,则不必要到达 36 { 37 dis[v]=dis[u]+1; 38 if (v==T) return 1;//到达终点即可 39 p[++tl]=v; 40 } 41 } 42 } 43 return 0; 44 } 45 int dfs(int u,int MM) 46 { 47 if (!MM||u==T) return MM; 48 int res=0; 49 for (int i=head[u];i!=-1;i=next[i]) 50 { 51 int v=rea[i],cost=val[i]; 52 if (dis[v]!=dis[u]+1) continue;//严格按照层次来进行 53 int x=dfs(v,min(MM,cost)); 54 if (x) 55 { 56 val[i]-=x,val[i^1]+=x; 57 MM-=x,res+=x; 58 if (!MM) break;//当前弧优化 59 } 60 } 61 if (MM==-1) dis[u]=-1; 62 return res; 63 } 64 int dinic() 65 { 66 int res=0; 67 while (bfs())//构造层次图,一旦无法到达终点,则增广结束,已经求得了最大流 68 { 69 int x=dfs(S,INF);//多路增广,每次初始为最大的流量 70 while (x) 71 { 72 res+=x; 73 x=dfs(S,INF); 74 } 75 } 76 return res; 77 } 78 int main() 79 { 80 while (~scanf("%d%d",&n,&m)) 81 { 82 cnt=1;//这是一个技巧,对反向边的构造有帮助 83 memset(head,-1,sizeof(head)); 84 S=n+1; 85 T=n+2; 86 int x,y; 87 for (int i=1;i<=n;i++) 88 { 89 scanf("%d",&x); 90 if (x==1) add(S,i,1),add(i,S,0); 91 else add(i,T,1),add(T,S,0); 92 } 93 for (int i=1;i<=m;i++) 94 { 95 scanf("%d%d",&x,&y); 96 add(x,y,1),add(y,x,1); 97 } 98 printf("%d\n",dinic()); 99 } 100 }