题意
给一个混合图(有向边、无向边均有),问是否存在欧拉回路
题解
经典题。
参见黑书p324,两种解法。
第一种是把边视为一类点,原来的点视为另一类点,构建二分图,进一步构建图
这里总结一下第二种做法:
基本定理是:对一个有向图,当且仅当其基图连通且每个点入度=出度。
先只看有向边,统计每个点入度和为
In[i]
,出度和为
Out[i]
然后只看无向边,对所有无向边任意定向。
我们要构一个网络,使得最后有流量的边不变,无流量的边反向。
则
∀x
,
In[x]
+有流量的入边数量+无流量的出边数量=
Out[x]
+有流量的出边数量+无流量的入边数量
即
有流量边的入边的数量
×2
+出边总容量=
Out[x]−In[x]
+有流量边的出边的数量
×2
+入边总容量
有流量边的入边的数量
×2
=有流量边的出边的数量
×2
+
Out[x]−In[x]
+入边总容量-出边总容量
注意这里入、出边总容量为无向图下,任意定向后的出边总数量,记为
In2[x],Out2[x]
则
有流量边的入边的数量=
(Out[x]−In[x]−Out2[x]+In2[x])/2
+有流量边的出边的数量
令
kx=Out[x]−In[x]−Out2[x]+In2[x]
不为偶数则无解。
所以我们按如下建图:
1. 当
kx>0
,建
(x,t,kx/2)
2. 当
kx<0
,建
(s,x,−kx/2)
3. 点之间按照定向后的边,建
(u,v,1)
若网络有可行流,即流量平衡方程能满足,则有解,否则无解。
#include <algorithm>
#include <bitset>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <string>
#include <vector>
const int INF = 0x3f3f3f3f;
const int MAXN = 210;
const int MAXM = 2010;
struct Dinic {
int n, tot, s, t;
int st[MAXN], st0[MAXN];
int lk[MAXM << 1], b[MAXM << 1], f[MAXM << 1]; bool del[MAXM << 1];
int Q[MAXN]; int l, r;
int d[MAXN];
int idx[MAXN][MAXN];
int su[MAXN];
void init() {
memset(st, 0, sizeof st); tot = 1;
memset(su, 0, sizeof su);
memset(idx, 0, sizeof idx);
}
void addedge(int u, int v, int w) {
// printf("%d %d %d\n", u, v, w);
if (!idx[u][v]) {
lk[++ tot] = st[u]; b[tot] = v; f[tot] = w; del[tot] = 0; st[u] = tot;
lk[++ tot] = st[v]; b[tot] = u; f[tot] = 0; del[tot] = 0; st[v] = tot;
idx[u][v] = tot-1; idx[v][u] = tot;
} else {
f[idx[u][v]] += w;
}
su[u] += w; su[v] += w;
}
bool BFS() {
memset(d, 0, sizeof d);
l = r = 0;
d[ Q[r ++] = s ] = 1;
for (; l != r; ++ l) {
int u = Q[l];
for (int i = st[u]; i; i = lk[i]) if (!del[i]) {
int v = b[i];
if (f[i] && !d[v]) {
d[v] = d[u] + 1;
Q[r ++] = v;
}
}
}
return d[t];
}
int DFS(int u, int a) {
if (u == t || a == 0) return a;
int flow = 0, df;
for (int& i = st0[u]; i; i = lk[i]) if (!del[i]) {
int v = b[i];
if (d[v] == d[u] + 1 && (df = DFS(v, std::min(a, f[i])))) {
f[i] -= df; f[i^1] += df;
a -= df; flow += df;
if (a == 0) break;
}
}
return flow;
}
void solve(int s, int t, int& flow) {
this->s = s; this->t = t;
while (BFS()) {
memcpy(st0, st, sizeof st0);
flow += DFS(s, INF);
}
}
void dt(int e) {
del[e] = del[e^1] = 1;
}
void aug(int s, int t, int& flow) {
this->s = s; this->t = t;
if (BFS()) {
memcpy(st0, st, sizeof st0);
flow += DFS(s, 1);
}
}
int flow(int u, int v) {
return f[idx[u][v]^1];
}
int cap(int u) {
return su[u];
}
} solver;
const int maxn = 210;
int n, m, s, t;
int k[maxn];
void solve() {
scanf("%d%d", &n, &m);
s = 0, t = n+1;
solver.init();
memset(k, 0, sizeof k);
for (int i = 1; i <= m; ++ i) {
int u, v, w; scanf("%d%d%d", &u, &v, &w);
if (w == 1) {
++ k[u]; -- k[v];
} else {
-- k[u]; ++ k[v];
solver.addedge(u, v, 1);
}
}
for (int u = 1; u <= n; ++ u) {
if (k[u]%2 != 0) { puts("impossible"); return; }
if (k[u] > 0)
solver.addedge(u, t, k[u]/2);
else if (k[u] < 0)
solver.addedge(s, u, -k[u]/2);
}
int flow = 0;
solver.solve(s, t, flow);
puts(flow == solver.cap(s) ? "possible" : "impossible");
}
int main() {
// freopen("poj1637.in", "r", stdin);
int kase; scanf("%d", &kase);
while (kase --) solve();
// for(;;);
return 0;
}