bzoj1934
1934: [Shoi2007]Vote 善意的投票
Time Limit: 1 Sec Memory Limit: 64 MBSubmit: 2406 Solved: 1498
[Submit][Status][Discuss]
Description
幼儿园里有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
1 0 0
1 2
1 3
3 2
Sample Output
1
HINT
在第一个例子中,所有小朋友都投赞成票就能得到最优解
最小割模型。
S向1的人建容量1的边,0的人向T建容量1的边。认识的人互相建容量1的边。
这样求出最小割后,与S相连的点集表示最终选1的人,与T相连表示选0,每条割边表示一个冲突。
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<queue> #define ll long long #define N 305 using namespace std; int n,m,S,T,tot,hd[N],d[N],vis[N],cur[N]; struct edge{int v,next,cap,flow;}e[N*N*4]; void adde(int u,int v,int c){ e[tot].v=v; e[tot].next=hd[u]; e[tot].cap=c; e[tot].flow=0; hd[u]=tot++; } bool bfs(){ queue<int>q; memset(vis,0,sizeof(vis)); q.push(S);d[S]=0; while(!q.empty()){ int u=q.front();q.pop();vis[u]=1; for(int i=hd[u];~i;i=e[i].next){ int v=e[i].v; if(e[i].cap<=e[i].flow||vis[v])continue; d[v]=d[u]+1;q.push(v); } } return vis[T]; } int dfs(int u,int a){ if(u==T||!a)return a; int fl=0,f; for(int i=hd[u];~i;i=e[i].next){ int v=e[i].v; if(d[v]==d[u]+1&&(f=dfs(v,min(e[i].cap-e[i].flow,a)))){ fl+=f;a-=f; e[i].flow+=f; e[i^1].flow-=f; if(a<=0)break; } } return fl; } int main(){ scanf("%d%d",&n,&m); memset(hd,-1,sizeof(hd)); S=0;T=n+1; for(int i=1;i<=n;i++){ int x; scanf("%d",&x); if(x)adde(S,i,1),adde(i,S,0); else adde(i,T,1),adde(T,i,0); } for(int i=1;i<=m;i++){ int a,b; scanf("%d%d",&a,&b); adde(a,b,1);adde(b,a,1); } int flow=0; while(bfs()){ for(int i=S;i<=T;i++)cur[i]=hd[i]; flow+=dfs(S,0x3f3f3f3f); } printf("%d",flow); return 0; }
If you live in the echo,
your heart never beats as loud.
如果你生活在回声里,
你的心跳声永远不会轰鸣作响。