简单思考一下,我们会发现对于
s
≠
0
s \neq 0
s=0 的点,它们有几个
+
1
+1
+1和几个
−
1
-1
−1都是固定了的。
我们不如只考虑
+
1
+1
+1,那么这就变成了一个二元组与点配对的问题。
很容易想到网络流。
我们将二元组作为左部点,分别向
U
[
i
]
U[i]
U[i]与
V
[
i
]
V[i]
V[i]连容量为
1
1
1的边。超级源点到每个左部点都连容量为
1
1
1的边,每个右部点向超级汇点连容量为其
+
1
+1
+1数量的边。
不过这样其实没能解决
s
=
0
s=0
s=0的点的问题。对于这部分点,我们需要先将其向一个低级汇点连容量为
∞
\infin
∞的边,接着从这个低级汇点向超级汇点连容量为
m
−
∑
s
[
u
]
=
1
i
n
d
e
g
[
u
]
m-\sum_{s[u]=1}indeg[u]
m−∑s[u]=1indeg[u](这里的
i
n
d
e
g
[
u
]
indeg[u]
indeg[u]是指,计算出的
u
u
u的
+
1
+1
+1数量)的边。
跑一个最大流,啪的一下,很快啊。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e4 + 5;
const int inf = 0x3f3f3f3f;
struct networkflow {
int tot;
int ver[MAXN << 3], cap[MAXN << 3], nxt[MAXN << 3], head[MAXN << 1];
networkflow() {
tot = 1;
memset(head, 0, sizeof(head));
}
void adde(int u, int v, int w) {
++tot;
ver[tot] = v;
cap[tot] = w;
nxt[tot] = head[u];
head[u] = tot;
}
void addedge(int u, int v, int w) {
adde(u, v, w);
adde(v, u, 0);
}
int d[MAXN << 1];
bool bfs(int s, int t) {
memset(d, 0, sizeof(d));
queue<int> q;
q.push(s);
d[s] = 1;
while (q.size()) {
int u = q.front();
q.pop();
for (int i = head[u]; i; i = nxt[i]) {
int v = ver[i];
if (cap[i] && !d[v]) {
d[v] = d[u] + 1;
q.push(v);
if (v == t) return true;
}
}
}
return false;
}
int dinic(int u, int flow, const int &t) {
if (u == t) return flow;
int rest = flow, k;
for (int i = head[u]; i; i = nxt[i]) {
int v = ver[i];
if (cap[i] && d[v] == d[u] + 1) {
k = dinic(v, min(rest, cap[i]), t);
if (!k) d[ver[i]] = 0;
cap[i] -= k;
cap[i ^ 1] += k;
rest -= k;
if (!rest) break;
}
}
return flow - rest;
}
int maxflow(int s, int t) {
int flow, res = 0;
while (bfs(s, t))
while (flow = dinic(s, inf, t))
res += flow;
return res;
}
} NF;
int N, M;
int S[MAXN], A[MAXN], U[MAXN], V[MAXN], deg[MAXN], indeg[MAXN];
int main() {
freopen("in.txt", "r", stdin);
ios::sync_with_stdio(false);
cin >> N >> M;
for (int i = 1; i <= N; i++)
cin >> S[i];
for (int i = 1; i <= N; i++)
cin >> A[i];
for (int i = 1; i <= M; i++) {
cin >> U[i] >> V[i];
++deg[U[i]];
++deg[V[i]];
NF.addedge(i + N, U[i], 1);
NF.addedge(i + N, V[i], 1);
}
for (int i = 1; i <= M; i++)
NF.addedge(N + M + 1, i + N, 1);
int sum_of_indeg = 0;
for (int i = 1; i <= N; i++) {
if (!S[i]) continue;
if ((deg[i] + A[i]) & 1) {
cout << "NO" << endl;
return 0;
}
indeg[i] = deg[i] + A[i] >> 1;
sum_of_indeg += indeg[i];
}
if (sum_of_indeg > M || sum_of_indeg < 0) {
cout << "NO" << endl;
return 0;
}
for (int i = 1; i <= N; i++)
if (S[i])
NF.addedge(i, N + M + 3, indeg[i]);
else
NF.addedge(i, N + M + 2, inf);
NF.addedge(N + M + 2, N + M + 3, M - sum_of_indeg);
int maxflow = NF.maxflow(N + M + 1, N + M + 3);
if (maxflow != M) {
cout << "NO" << endl;
return 0;
} else {
cout << "YES" << endl;
for (int i = 1; i <= M; i++) {
int idx1 = (i - 1) * 4 + 2, idx2 = (i - 1) * 4 + 4;
int u = (!NF.cap[idx1] ? NF.ver[idx2] : NF.ver[idx1]);
int v = U[i] ^ V[i] ^ u;
cout << u << " " << v << endl;
}
}
return 0;
}