1934: [Shoi2007]Vote 善意的投票
Time Limit: 1 Sec Memory Limit: 64 MB
Submit: 1551 Solved: 951
[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
Sample Output
1
HINT
在第一个例子中,所有小朋友都投赞成票就能得到最优解
Source
Day2
这道题啊,刚看到我还真没确定是网络流,不过仔细想想,有了点眉目,想到建图策略后这道题就水了。。。
首先超级源超级汇,超级源连接初始意愿为1的小朋友,超级汇连接初始意愿为0的小朋友,好朋友相连(双向边!!),边权都为1,Dinic出答案。。
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int dis[9000]={0};
int q[9000]={0},h,t;
struct data{
int to,next,v;
}edge[100001];
int head[9000]={0};
int cnt=1;
int yy[400]={0};
int n,m,ans;
void add(int u,int v,int w)
{
cnt++;
edge[cnt].next=head[u];
head[u]=cnt;
edge[cnt].v=w;
edge[cnt].to=v;
}
void init()
{
scanf("%d%d",&n,&m);
for (int i=1; i<=n; i++)
{
scanf("%d",&yy[i]);
if (yy[i]==1)
{
add(0,i,1);
add(i,0,0);
}
else
{
add(i,n+1,1);
add(n+1,i,0);
}
}
for (int i=1; i<=m; i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y,1);
add(y,x,1);
}//重要的是双向边,一开始忽略了。。。
}
bool bfs()
{
memset(dis,-1,sizeof(dis));
q[1]=0;dis[0]=1;
h=0; t=1;
while (h<t)
{
int j=q[++h],i=head[j];
while (i)
{
if (dis[edge[i].to]<0 && edge[i].v>0)
{
dis[edge[i].to]=dis[j]+1;
q[++t]=edge[i].to;
}
i=edge[i].next;
}
}
if (dis[n+1]>0)
return true;
else
return false;
}
int dfs(int loc,int low)
{
int now=0;
if (loc==n+1) return low;
int i=head[loc];
while (i)
{
if (edge[i].v>0 && dis[edge[i].to]==dis[loc]+1 && (now=dfs(edge[i].to,min(low,edge[i].v))))
{
edge[i].v-=now;
edge[i^1].v+=now;
return now;
}
i=edge[i].next;
}
return 0;
}
int main()
{
init();
while (bfs())
{
int now=0;
while ((now=dfs(0,0x7fffffff)))
ans+=now;
}
printf("%d",ans);
return 0;
}