题面:
题意
给定n个节点和m条边以及每个节点的期望度数,问是否可以通过删去一些边使每个节点都满足期望度数。
根据官方的解法应该是带花树的一般图匹配算法,但我不会 ,因此突发奇想可不可以转化为最大流的模型。
老套路,先拆分点,以样例三为例,我们把1拆成1和1’, 将2拆成2和2’, 将3拆成3和3’。如果一个节点的期望度数为2,我们就将i与S连一条流量为2的2边,再将i’与T连一条流量为2的边。其余点按如图所示的连接方法,最后求出最大流为2。
最后跑一遍最大流的板子,只要最后汇点的流量总和等于所有点的度数即源点流出的流量时,输出Yes,否则输出No。
AC Code
#include <bits/stdc++.h>
using namespace std;
const int N = 200 + 5;
const int M = 10000 + 5;
int n, m, a[N], cnt, h[N], s, t;
int cur[N], dep[N];
int maxflow, ss;
struct edge {
int to, next, vi;
}e[2*M];
void add(int u, int v, int w) {
e[cnt].to = v;
e[cnt].vi = w;
e[cnt].next = h[u];
h[u] = cnt++;
e[cnt].to = u;
e[cnt].vi = 0;
e[cnt].next = h[v];
h[v] = cnt++;
}
bool bfs() {
for (int i = 0; i <= 2*n+2; i++) cur[i] = h[i], dep[i] = -1;
queue<int> q;
q.push(s);
dep[s] = 0;
while (q.size()) {
int u = q.front();
q.pop();
if (u == t) break;
for (int i = h[u]; ~i; i = e[i].next) {
int v = e[i].to;
if (e[i].vi && dep[v] == -1) {
dep[v] = dep[u] + 1;
q.push(v);
}
}
}
if (dep[t] > -1) return true;
else return false;
}
int dfs(int u, int mx) {
int a;
if (u == t) return mx;
for (int i = cur[u]; ~i; i = e[i].next) {
int v = e[i].to;
cur[u] = i;
if (e[i].vi&& dep[v] == dep[u] + 1 && (a = (dfs(v, min(mx, e[i].vi))))) {
e[i].vi -= a;
e[i ^ 1].vi += a;
return a;
}
}
return 0;
}
void dinic() {
int res;
while (bfs()) {
res = dfs(s, 0x3f3f3f);
if (!res) break;
maxflow += res;
}
}
int main() {
while (cin >> n >> m) {
memset(h, -1, sizeof h);
maxflow = 0;
cnt = 0;
ss = 0;
s = n * 2 + 1, t = n * 2 + 2;
for (int i = 1; i <= n; i++) cin >> a[i], ss += a[i];
for (int i = 0; i < m; i++) {
int x, y;
cin >> x >> y;
add(x, y + n, 1);
add(y, x + n, 1);
}
for (int i = 1; i <= n; i++) {
if (a[i] == 2) {
add(s, i, 2);
add(i+n, t, 2);
}
else {
add(s, i, 1);
add(i+n, t, 1);
}
}
dinic();
if (maxflow == ss) cout << "Yes" << endl;
else cout << "No" << endl;
}
}
’