题目描述
幼儿园里有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 3
1 0 0
1 2
1 3
3 2
输出 #1
1
说明/提示
2≤n≤300,1≤m≤n(n-1)/2。
源点S表示支持睡觉,汇点S表示不睡觉。S点连向支持睡觉的小朋友一条流量为1的边,不支持睡觉的小朋友连向T点一条流量为1的边。互为好友关系的小朋友直接连有流量为1的双向边。
求得最小割,将小朋友划分到两个不同的集合。最小割的代价就是最小冲突数
#include<bits/stdc++.h>
using namespace std;
struct node{
int nx,v,w;
}edge[120000];
int head[500],tot = 1,s,t,dis[500];
inline void add(int u,int v,int w)
{
edge[++tot].v = v;
edge[tot].w = w;
edge[tot].nx = head[u];
head[u] = tot;
edge[++tot].v = u;
edge[tot].w = 0;
edge[tot].nx = head[v];
head[v] = tot;
}
bool bfs()
{
memset(dis,-1,sizeof(dis));
queue<int> q;
q.push(s);
dis[s] = 0;
while (!q.empty())
{
int u = q.front(); q.pop();
for (int i = head[u];i;i = edge[i].nx)
{
int v = edge[i].v;
if (dis[v] == -1 && edge[i].w > 0)
{
dis[v] = dis[u] + 1;
q.push(v);
}
}
}
return dis[t] != -1;
}
int dfs(int u,int exp)
{
if (u == t) return exp;
int flow = 0;
for (int &i = head[u];i;i = edge[i].nx)
{
int v = edge[i].v;
if (dis[v] == dis[u] + 1 && edge[i].w > 0)
{
int tmp = dfs(v,min(exp,edge[i].w));
if (tmp == 0) continue;
edge[i].w -= tmp;
edge[i^1].w += tmp;
exp -= tmp;
flow += tmp;
if (exp == 0) break;
}
}
return flow;
}
int dinic()
{
int ans = 0,tmp[500];
for (int i = 1;i<=302;i++) tmp[i] = head[i];
while (bfs())
{
ans += dfs(s,INT_MAX);
for (int i = 1;i<=302;i++) head[i] = tmp[i];
}
return ans;
}
int main()
{
int n,m,a[500];
scanf("%d%d",&n,&m);
s = 301,t = 302;
for (int i = 1;i<=n;i++)
{
scanf("%d",&a[i]);
if (a[i]) add(s,i,1);
else add(i,t,1);
}
for (int i = 1,u,v;i<=m;i++)
{
scanf("%d%d",&u,&v);
add(u,v,1);
add(v,u,1);
}
printf("%d",dinic());
return 0;
}