再补充一点我的理解:为什么要建立新的源汇点?就是为了让每个点都保证出度及入度的相等。所以对于缺少入度的点v, 建边(s,v,x),对于缺少出度的点v,建边(s,v,-x),注意x = (v出度 - v入度) / 2。最后跑一次最大流,按照有流量的边建立有向边即可。
代码如下:
#include <stdio.h> #include <string.h> #include <memory.h> #include <algorithm> #define MS0(X) memset(X, 0, sizeof X) #define MS1(X) memset(X, -1, sizeof X) #define MC(X, Y) memcpy(X, Y, sizeof X) using namespace std; const int oo = 0x3f3f3f3f; const int maxE = 1000000; const int maxN = 200; struct Edge{ int v, c, n; Edge(){} Edge(int Var, int Cap, int Next): v(Var), c(Cap), n(Next){} }; Edge edge[maxE], qedge[maxE]; int adj[maxN], qadj[maxN], l, ll; int d[maxN], num[maxN], cur[maxN], pre[maxN]; int Q[maxE], head, tail; int s, t, nv; int deg[maxN], put[maxE], cnt; void addedge(int u, int v, int c){ edge[l] = Edge(v, c, adj[u]); adj[u] = l++; edge[l] = Edge(u, 0, adj[v]); adj[v] = l++; } void add(int u, int v){ qedge[ll] = Edge(v, 0, qadj[u]); qadj[u] = ll++; } void REV_BFS(){ MS0(num); MS1(d); head = tail = 0; d[t] = 0; num[0] = 1; Q[tail++] = t; while(head != tail){ int u = Q[head++]; for(int i = adj[u]; ~i; i = edge[i].n){ int v = edge[i].v; if(~d[v]) continue; Q[tail++] = v; d[v] = d[u] + 1; num[d[v]]++; } } } int ISAP(){ MC(cur, adj); REV_BFS(); int flow = 0, u = pre[s] = s, i; while(d[s] < nv){ if(u == t){ int f = oo, neck; for(i = s; i != t; i = edge[cur[i]].v){ if(f > edge[cur[i]].c){ f = edge[cur[i]].c; neck = i; } } for(i = s; i != t; i = edge[cur[i]].v){ edge[cur[i]].c -= f; edge[cur[i] ^ 1].c += f; } flow += f; u = neck; } for(i = cur[u]; ~i; i = edge[i].n) if(d[u] == d[edge[i].v] + 1 && edge[i].c) break; if(~i){ cur[u] = i; pre[edge[i].v] = u; u = edge[i].v; } else{ if(!(--num[d[u]])) break; int mind = nv; for(i = adj[u]; ~i; i = edge[i].n){ if(edge[i].c && mind > d[edge[i].v]){ cur[u] = i; mind = d[edge[i].v]; } } d[u] = mind + 1; num[d[u]]++; u = pre[u]; } } return flow; } void print(int u){ for(int i = qadj[u]; ~i; i = qedge[i].n){ if(!qedge[i].c){ qedge[i].c = 1; print(qedge[i].v); } } put[cnt++] = u; } void init(){ MS1(adj); MS1(qadj); MS0(deg); l = ll = 0; cnt = 0; } void work(){ int T, n, m, u, v, flag, ans; char str[5]; for(scanf("%d", &T); T; T--){ init(); scanf("%d%d", &n, &m); for(int i = 0; i < m; ++i){ scanf("%d%d%s", &u, &v, str); if(str[0] == 'D') add(u, v); else addedge(u, v, 1); ++deg[u]; --deg[v]; } flag = 1; ans = 0; s = 0; t = n + 1; nv = t + 1; for(int i = 1; i <= n; ++i){ if(deg[i] & 1){ flag = 0; break; } if(deg[i] > 0){ addedge(s, i, deg[i] / 2); ans += deg[i] / 2; } else if(deg[i] < 0) addedge(i, t, (-deg[i]) / 2); } if(!flag || ans != ISAP()){ printf("No euler circuit exist\n"); } else{ for(u = 1; u <= n; ++u){ for(int i = adj[u]; ~i; i = edge[i].n){ int v = edge[i].v; if(v == s || v == t || !edge[i].c) continue; add(u, v); } } print(1); for(int i = cnt - 1; ~i; --i) printf("%d%c", put[i], i ? ' ' : '\n'); } if(T > 1) printf("\n"); } } int main(){ work(); return 0; }