http://acm.pku.edu.cn/JudgeOnline/problem?id=1273
给一组边 有的是有向边有的是无向边 问是否存在欧拉回路
我们知道如果每个点入度等于出度 就存在欧拉回路
这里有无向边 可以任意指定方向, 有向边已经没法改了 只统计度数 不加边
那我们不妨指定方向为u->v 然后尝试更改这些边的方向来使每个点入度等于出度
使边u->v反向 那么u的出度-1 入度+1, v出度+1 入度-1
可以开个det数组 存每个点的出度减入度 通过改变边u->v的方向 使det[u]-=2, det[v]+=2
det为0时这个点出度等于入度 也就是说如果det为奇数一定没有欧拉回路
det[i]>0 加边st->i(权值为det[i]/2) det[i]<0 加边i->ed(权值为-det[i]/2) (权值表示需要逆的边数)
跑个网络流 如果每个st出发的边都为满流 就有欧拉回路
因为考虑一个st...i...j...k...ed的增广路
路径上的边全部反向 det[i]-=2 det[k]+=2 det[j]不变
如果能给每个st出发的边都加上满流 那么就能所有点det为0
#include<cstdio> #include<cstring> using namespace std; const int maxn = 207, maxm = 1007, inf = 0x3f3f3f3f; struct Edge{ int u, v, w, f, nxt; Edge(){} Edge(int u, int v, int w, int f, int nxt):u(u), v(v), w(w), f(f), nxt(nxt){} }edge[maxm*2]; int head[maxn], cur[maxn], gap[maxn], dep[maxn], pre[maxn], n, m, tot, st, ed; int in[maxn], out[maxn], change[maxn]; void addedge(int u, int v, int w){ edge[tot] = Edge(u, v, w, 0, head[u]); head[u] = tot++; edge[tot] = Edge(v, u, 0, 0, head[v]); head[v] = tot++; } void init(){ tot = 0; memset(head, -1, sizeof head); memset(in, 0, sizeof in); memset(out, 0, sizeof out); memset(change, 0, sizeof change); } int sap(){ memset(dep, 0, sizeof dep); memset(gap, 0, sizeof gap); memcpy(cur, head, sizeof head); int u = st; gap[0] = n; pre[u] = -1; int ans = 0; while(dep[st] < n){ if(u == ed){ int MIN = inf; for(int i = pre[ed]; ~i; i = pre[edge[i].u]){ if(MIN > edge[i].w-edge[i].f) MIN = edge[i].w-edge[i].f; } for(int i = pre[ed]; ~i; i = pre[edge[i].u]){ edge[i].f += MIN; edge[i^1].f -= MIN; } ans += MIN; u = st; continue; } int v= 0; bool flag = false; for(int i = cur[u]; ~i; i = edge[i].nxt){ v = edge[i].v; if(edge[i].w-edge[i].f && dep[u] == dep[v]+1){ pre[v] = i; cur[u] = i; flag = true; break; } } if(flag){ u = v; continue; } int MIN = n; for(int i = head[u]; ~i; i = edge[i].nxt){ int v = edge[i].v; if(MIN > dep[v] && edge[i].w-edge[i].f){ MIN = dep[v]; cur[u] = i; } } gap[dep[u]]--; if(!gap[dep[u]]) return ans; dep[u] = MIN+1; gap[dep[u]]++; if(u != st) u = edge[pre[u]].u; } return ans; } bool judge(){ int sum = 0; for(int i = 1; i <= n; i++){ out[i] = out[i]-in[i]; if(!change[i] && out[i]) return false; if(out[i]&1) return false; out[i] /= 2; if(out[i]<0){ out[i] = -1*out[i]; addedge(i, ed, out[i]); } else if(out[i] == 0) continue; else{ sum += out[i]; addedge(st, i, out[i]); } } n+=2; // mmmmmmp int ans = sap(); //printf("%d %d ", sum, ans); return sum == ans; } int main(){ int t; scanf("%d", &t); while(t--){ init(); scanf("%d%d", &n, &m); st = 0, ed = n+1; while(m--){ int u, v, jud; scanf("%d%d%d", &u, &v, &jud); out[u]++; in[v]++; if(!jud){ addedge(u, v, 1); change[u] = change[v] = 1; } } if(judge()) printf("possible "); else puts("impossible"); } return 0; }