设源点S,汇点T
对于所有赞成的人 从S连一条边到他们对应的点上 容量设为1
对于所有反对的人 从他们对应的点上连一条边到T 容量为1
对于所有有朋友 关系的a和b 在他们之间连一条无向边 容量为1
最小割可以用dinic跑出来 即所求答案
只要记好朋友之间的冲突总数就好了
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int maxn = 304;
const int inf = 0x7f7f7f7f;
const int maxm = 4500;
int n, m,S,T;
struct edge {
int v, c, next;
}e[maxn*maxn<<1];
int p[maxn], eid = 0,d[maxn];
inline void ins(int u, int v, int c) {
e[eid].v = v; e[eid].c = c; e[eid].next = p[u]; p[u] = eid++;
}
inline void addedge(int u, int v, int c) {
ins(u, v, c);
ins(v, u, 0);
}
bool bfs() {
memset(d, -1, sizeof(d));
queue<int> q;
q.push(S);
d[S] = 0;
while (!q.empty()) {
int u = q.front(); q.pop();
for (int i = p[u]; ~i; i = e[i].next) {
int v = e[i].v;
if (e[i].c > 0 && d[v] == -1) {
d[v] = d[u] + 1;
q.push(v);
}
}
}
return (d[T] != -1);
}
int dfs(int u, int flow) {
if (u == T) return flow;
int res = 0;
for (int i = p[u]; ~i; i = e[i].next) {
int v = e[i].v;
if (e[i].c > 0 && d[v] == d[u] + 1) {
int tmp = dfs(v, min(flow, e[i].c));
res += tmp;
flow -= tmp;
e[i].c -= tmp;
e[i ^ 1].c += tmp;
if (flow == 0) break; //饱和
}
}
if (res == 0) d[u] = -1;
return res;
}
int dinic() {
int res = 0;
while (bfs()) {
res += dfs(S, 0x7f7f7f7f);
//printf("%d\n", res);
}
return res;
}
inline void init() {
memset(p, -1, sizeof(p));
eid = 0;
}
inline int read() {
int s = 0, f = 1; char c = getchar(); while (c<'0' || c>'9') { if (c == '-') f = -1; c = getchar(); }
while (c >= '0'&&c <= '9') { s = s * 10 + c - '0'; c = getchar(); }
return s*f;
}
int main() {
n = read(); m = read();
int a, b;
S = 0; T = n + 1;
init();
for (int i = 1; i <= n; i++) {
if (read() == 1) addedge(S, i, 1);
else addedge(i, T, 1);
}
for (int i = 1; i <= m; i++) {
a = read(); b = read();
addedge(a, b, 1); //好朋友意愿不同也要计算冲突
addedge(b, a, 1);
}
printf("%d", dinic());
//getchar();
return 0;
}