考虑最小割数学形式
考虑一个点在 (S) 集合里是 0 在 (T) 集合里是 1
那么一个点是 1 时,它只有在零里才有贡献连边 (x o T) 否则连边 (S o x)
当两个点时朋友时,他们在不同的集合里才会有贡献,连边 (x o y), (y o x)
#include <bits/stdc++.h>
using namespace std;
#define rg register
#define rep(i ,a, b) for(int i = a; i <= b; ++i)
#define per(i, a, b) for(int i = a; i >= b; --i)
#define I inline
const int N = 305, M = (N * N) << 5;
int head[N], ver[M], nxt[M], flow[M], tot = 1;
I void add(int x, int y, int f){
ver[++tot] = y;
nxt[tot] = head[x];
head[x] = tot;
flow[tot] = f;
}
I void adds(int x, int y, int f){
add(x, y, f);
add(y, x, 0);
}
int S, T, cur[N], dis[N];
I int bfs(){
memset(dis, 0, sizeof dis);
queue<int> q;
q.push(S); dis[S] = 1;
while(!q.empty()){
int x = q.front(); q.pop();
cur[x] = head[x];
for(int i = head[x]; i; i = nxt[i]){
int y = ver[i];
if(flow[i] && !dis[y]){
dis[y] = dis[x] + 1;
q.push(y);
}
}
}
return dis[T];
}
int dfs(int x, int f){
if(x == T) return f;
int used = 0;
for(int &i = cur[x]; i; i = nxt[i]){
int y = ver[i];
if(flow[i] && dis[y] == dis[x] + 1){
int w = dfs(y, min(flow[i], f - used));
if(w){
flow[i] -= w;
flow[i ^ 1] += w;
used += w;
if(used == f) return f;
}
}
}
if(!used) dis[x] = false;
return used;
}
I int dinic(){
int res = 0;
while(bfs()) res += dfs(S, 0x3f3f3f3f);
return res;
}
int n, m;
signed main(){
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> n >> m;
int x, y; S = 0, T = n + 1;
rep(i, 1, n){
cin >> x;
if(x){
adds(i, T, 1);
}else adds(S, i, 1);
}
rep(i, 1, m){
cin >> x >> y;
adds(x, y, 1); adds(y, x, 1);
}
cout << dinic() << endl;
return 0;
}