1. 程式人生 > >混合圖歐拉回路

混合圖歐拉回路

所有 ace .cn geo urn 我們 方向 online n)

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\n", 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\n"); else puts("impossible"); } return 0; }

混合圖歐拉回路