BZOJ1934【SHOI2007】善意的投票 <网络流>

善意的投票

题目描述
幼儿园里有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不会重复。
输出格式:
只需要输出一个整数,即可能的最小冲突数。

输入输出样例
输入样例:
3 3
1 0 0
1 2
1 3
3 2
输出样例:
1

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

标签:网络流,最小割

最小割见图如下:
如果本人意见为0,则与源点相连,反之与汇点相连。
对于每对朋友关系,互相连边。
所有边的容量均为1,跑最大流最小割即可。

原理:对于每个人,如果有朋友与他意见不合,则他要么割自己到源点(汇点)的一条边,要么割与朋友的边,代价等于容量。

附上AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define MAX_N 300
#define MAX_M MAX_N*(MAX_N-1)*2 
#define INF 2147483647
using namespace std;
int n, m, s, t;
int d[MAX_N+5], first[MAX_N+5], cnt;
struct node {int v, c, next;} E[MAX_M+5];
void Init() {
	cnt = 0;
	memset(first, -1, sizeof(first));
}
void Insert(int u, int v, int c) {
	E[cnt].v = v, E[cnt].c = c;
	E[cnt].next = first[u];
	first[u] = cnt++;
}
void AddEdge(int u, int v, int c) {
	Insert(u, v, c);
	Insert(v, u, 0);
}
bool BFS() {
	memset(d, -1, sizeof(d));
	queue <int> que;
	que.push(s), d[s] = 0;
	while (!que.empty()) {
		int u = que.front();
		for (int i = first[u]; i != -1; i = E[i].next) {
			int v = E[i].v;
			if (E[i].c && d[v] == -1) {
				d[v] = d[u]+1;
				que.push(v);
			}
		}
		que.pop();
	}
	return (d[t] != -1);
}
int DFS(int u, int flow) {
	if (u == t)	return flow;
	int ret = 0;
	for (int i = first[u]; i != -1; i = E[i].next) {
		int v = E[i].v;
		if (E[i].c && d[v] == d[u]+1) {
			int tmp = DFS(v, min(flow, E[i].c));
			if (!tmp)	continue;
			flow -= tmp, E[i].c -= tmp;
			ret += tmp, E[i^1].c += tmp;
			if (!flow)	break;
		}
	}
	if (!ret)	d[u] = -1;
	return ret;
}
int Dinic() {
	int ret = 0;
	while (BFS())
		ret += DFS(s, INF);
	return ret;
}
int main() {
	Init();	scanf("%d%d", &n, &m);
	s = 0, t = n+1;
	for (int i = 1; i <= n; i++) {
		int f;	scanf("%d", &f);
		if (f == 1) {
			AddEdge(s, i, 1);
		} else {
			AddEdge(i, t, 1);
		}
	}
	for (int i = 0; i < m; i++) {
		int u, v;	scanf("%d%d", &u, &v);
		AddEdge(u, v, 1);
		AddEdge(v, u, 1);
	}
	printf("%d", Dinic());
	return 0;
}
posted @ 2017-09-22 18:17  Azrael_Death  阅读(115)  评论(0编辑  收藏  举报