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

Problem

善意的投票

题目描述

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

输入输出格式

输入格式
文件的第一行只有两个整数nnmm,保证有2n3002\le n\le 3001mn×(n1)/21\le m\le n\times (n-1)/2
其中nn代表总人数,mm代表好朋友的对数。文件第二行有nn个整数,第ii个整数代表第ii个小朋友的意愿,当它为11时表示同意睡觉,当它为00时表示反对睡觉。接下来文件还有mm行,每行有两个整数iijj。表示iijj是一对好朋友,我们保证任何两对iijj不会重复。
输出格式
只需要输出一个整数,即可能的最小冲突数。

输入输出样例

输入样例

1
2
3
4
5
3 3
1 0 0
1 2
1 3
3 2

输出样例

1
1

说明

2n3002\le n\le 3001mn×(n1)/21\le m\le n\times (n-1)/2

标签:网络流 最小割

Solution

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

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

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#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;
}