洛谷 P2057 善意的投票

来源:互联网 发布:淘宝宝贝怎么修改类目 编辑:程序博客网 时间:2024/05/07 17:41

题目描述

幼儿园里有n个小朋友打算通过投票来决定睡不睡午觉。对他们来说,这个问题并不是很重要,于是他们决定发扬谦让精神。虽然每个人都有自己的主见,但是为了照顾一下自己朋友的想法,他们也可以投和自己本来意愿相反的票。我们定义一次投票的冲突数为好朋友之间发生冲突的总数加上和所有和自己本来意愿发生冲突的人数。

我们的问题就是,每位小朋友应该怎样投票,才能使冲突数最小?

输入输出格式

输入格式:

文件的第一行只有两个整数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不会重复。

输出格式:

只需要输出一个整数,即可能的最小冲突数。

输入输出样例

输入样例#1:
3 31 0 01 21 33 2
输出样例#1:
1







说明

2≤n≤300,1≤m≤n(n-1)/2。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

(网络流)割~

先建一个源点0,一个汇点n+1,对于所有同意的点,从0连边;所有不同意的点,向汇点连边,然后朋友之间连双向边,跑一遍割点即可~

T到飞起,后来才发现是因为数组开小了……无力吐槽……

(现在才分清楚割和割点,好神奇啊~)


#include<cstdio>#include<cstring>#include<iostream>#include<queue>using namespace std;int n,m,x,y,fi[120010],ne[120010],w[120010],v[120010],cnt,ans,now,dis[120010];int read(){int f=1,totnum=0;char s=getchar();while(s<'0' || s>'9') {if(s=='-') f=-1;s=getchar();}while(s>='0' && s<='9') {totnum=totnum*10+s-'0';s=getchar();}return f*totnum;}void add(int u,int vv,int val){w[++cnt]=vv;v[cnt]=val;ne[cnt]=fi[u];fi[u]=cnt;w[++cnt]=u;v[cnt]=-val;ne[cnt]=fi[vv];fi[vv]=cnt;}bool bfs(){queue<int> q;q.push(0);dis[0]=1;while(!q.empty()){int k=q.front();q.pop();for(int i=fi[k];i;i=ne[i])  if(!dis[w[i]] && v[i]>0)  {  dis[w[i]]=dis[k]+1;q.push(w[i]);  if(w[i]==n) return 1;  }}return 0;}int dfs(int u,int vv){if(u==n) return vv;int kkz;for(int i=fi[u];i;i=ne[i])  if(v[i]>0 && dis[u]+1==dis[w[i]] && (kkz=dfs(w[i],min(vv,v[i]))))  {  v[i]-=kkz;v[i^1]+=kkz;return kkz;  }return 0;}int main(){n=read();m=read();n++;cnt=1;for(int i=1;i<n;i++){x=read();if(x) add(0,i,1);else add(i,n,1);}while(m--){x=read();y=read();add(x,y,1);add(y,x,1);}while(bfs())  while(now=dfs(0,999999999)) ans+=now;printf("%d\n",ans);return 0;}


1 0
原创粉丝点击