题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1956
引用discuss里的题解思路:
简单来说就是利用网络流里反向弧的特征来平衡每个点的度,能变向的只有无向边,所以有向边要删除。
以下为dinic算法的AC代码(G++)
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxm = 200 + 5;
const int maxs = 1000 + 5;
int n, m, s, degree[maxm];
int cnt, head[maxs << 1], cur[maxm], depth[maxm];
int start, tend, toCheck[maxs];
int graph[maxm][maxm];
struct edge {
int to, cap, next;
}e[maxs];
void addedge(int u, int v, int w) {
e[cnt].to = v;
e[cnt].cap = w;
e[cnt].next = head[u];//记录u点之前的最后一条边
head[u] = cnt++;//记录u的最后一条边
}
bool bfs() {
memset(depth, -1, sizeof(depth));
int Thead = 0, Ttail = 0;
int Q[maxs << 1];//队列
Q[Ttail++] = start;
depth[start] = 0;
while (Thead < Ttail) {
int u = Q[Thead];
if (u == tend)return true;
for (int i = head[u]; i != -1; i = e[i].next) {
int v = e[i].to;
if (depth[v] == -1 && e[i].cap > 0) {
//没有分配层数且仍有容量
depth[v] = depth[u] + 1;
Q[Ttail++] = v;
}
}
Thead++;
}
return false;
}
int dfs(int u, int cap) {
if (u == tend)return cap;
int flow = 0, f;
for (int& i = cur[u]; i != -1; i = e[i].next) {
if ((depth[u] + 1 == depth[e[i].to]) && e[i].cap > 0) {
int f = dfs(e[i].to, min(cap - flow, e[i].cap));
if (f > 0) {
e[i].cap -= f;
e[i ^ 1].cap += f;
flow += f;
if (flow == cap)break;
}
}
}
if (!flow)depth[u] = -2;//防止重搜
return flow;
}
int main(void) {
scanf("%d", &n);
while (n--) {
scanf("%d %d", &m, &s);
memset(head, -1, sizeof(head));
memset(degree, 0, sizeof(degree));
memset(graph, 0, sizeof(graph));
start = 0;
tend = m + 1;
for (int i = 0; i < s; i++) {
int x, y, d;
scanf("%d %d %d", &x, &y, &d);
degree[x]++;
degree[y]--;
if (!d) graph[x][y]++;
}
cnt = 0;
for (int i = 1; i <= m; i++)
for (int j = 1; j <= m; j++) {
if (graph[i][j]) {
addedge(i, j, graph[i][j]);
addedge(j, i, 0);
}
}
int len = 0;
bool flag = true;
for (int i = 1; i <= m; i++)
if (degree[i] & 1) {
flag = false;
break;
}
if (!flag) {
printf("impossible\n");
continue;
}
for (int i = 1; i <= m; i++) {
if (degree[i] > 0) {
toCheck[len++] = cnt;
addedge(start, i, degree[i] / 2);
addedge(i, start, 0);
}
else if (degree[i] < 0) {
addedge(i, tend, -degree[i] / 2);
addedge(tend, i, 0);
}
}
while (bfs()) {//tend在层次图中
for (int i = 0; i <= m + 1; i++)
cur[i] = head[i];
while (dfs(start, inf));//找的到增广路
}
for (int i = 0; i < len; i++) {
int u = toCheck[i];
if (e[u].cap) {
flag = false;
break;
}
}
if (flag)printf("possible\n");
else printf("impossible\n");
}
return 0;
}