计算每一个节点的入度出度,然后判断每个节点的入度出度之差是否为偶数
如果不是则不存在欧拉回路,反之则有可能通过改变无向边的方向从而使得图中存在欧拉回路
怎么变呢,如果一个点的入度大于出度,那么我们必然需要将该点所连接的无向边改变方向,然而改变之后又会影响到其他的结点,
注意这个影响的过程,我们可以将这种影响的过程看做度数的转移,比如结点1和2之间有一条无向边,我最初给这条边指定了一个方向,比如1指向2
当我们改变这个方向时,1的出度减少1,入度增加1,而2的出度增加1,入度减少1,
回顾这个过程,结点1的最初的状态是需要一个入度,而2可以给1提供一个入度,所以可以看做节点2向节点1转移了一个货物
当然这样做的条件是,1需要,2有,也就是对于某一个结点来说它的入度比出度大2,那么他就是需要一个出度,反之可以提供一个入度
然后我们依照这个标准建图求一个最大流就行了,当然必须要添加2个源点
关于欧拉回路的打印,百度吧,或者直接参考刘汝佳代码即可
#include<iostream> #include<cmath> #include<cstdio> #include<cstdlib> #include<cstring> #include<iomanip> #include<assert.h> #include<ctime> #include<vector> #include<list> #include<map> #include<set> #include<sstream> #include<stack> #include<queue> #include<string> #include<bitset> #include<algorithm> using namespace std; #define me(s) memset(s,0,sizeof(s)) #define pf printf #define sf scanf #define Di(x) int x;scanf("%d",&x) #define in(x) inp(x) #define in2(x,y) inp(x),inp(y) #define in3(x,y,z) inp(x),inp(y),inp(z) #define ins(x) scanf("%s",x) #define ind(x) scanf("%lf",&x) #define IO ios_base::sync_with_stdio(0);cin.tie(0) #define READ freopen("C:/Users/ASUS/Desktop/in.txt","r",stdin) #define WRITE freopen("C:/Users/ASUS/Desktop/out.txt","w",stdout) template<class T> void inp(T &x) {//读入优化 char c = getchar(); x = 0; for (; (c < 48 || c>57); c = getchar()); for (; c > 47 && c < 58; c = getchar()) { x = (x << 1) + (x << 3) + c - 48; } } typedef pair <int, int> pii; typedef long long ll; typedef unsigned long long ull; const int inf = 0x3f3f3f3f; const int mod = 1e9 + 7; const double pi = acos(-1.0); const double eps = 1e-15; const int maxn=100+5; struct Edge{ int from,to,cap,flow; Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){} }; struct EdmondsKarp{ int n,m; vector<Edge> edges; vector<int>G[maxn];//邻接表,G[i][j]表示节点i的第j条边在edges数组中的需要 int a[maxn];//当起点到i的可改进量 int p[maxn];//最短路树上p的入弧编号 void init(int n){ for(int i=0;i<n;i++) G[i].clear(); edges.clear(); } void AddEdge(int from,int to,int cap){ edges.push_back(Edge(from,to,cap,0)); edges.push_back(Edge(to,from,0,0));//反向弧 m=edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } int Maxflow(int s,int t){ int flow=0; for(;;){ //开始寻找增广路 memset(a,0,sizeof(a)); queue<int> Q; Q.push(s); a[s]=inf; while(!Q.empty()){ int x=Q.front();Q.pop(); for(int i=0;i<G[x].size();i++){ Edge &e=edges[G[x][i]]; if(!a[e.to]&&e.cap>e.flow){ p[e.to]=G[x][i]; a[e.to]=min(a[x],e.cap-e.flow); Q.push(e.to); } } if(a[t]) break;//找到了一条增广路 } if(!a[t]) break;//不存在增广路,当前流就是最大流 for(int u=t;u!=s;u=edges[p[u]].from){ edges[p[u]].flow+=a[t]; edges[p[u]^1].flow-=a[t]; } flow+=a[t]; } return flow; } }; EdmondsKarp g; const int maxm=500+5; //edges size int u[maxm],v[maxm],diff[maxm],id[maxm],directed[maxm]; int n,m; vector<int> G[maxn]; vector<int> vis[maxn]; vector<int> path; void euler(int u) { for(int i = 0; i < G[u].size(); i++) if(!vis[u][i]) { vis[u][i] = 1; euler(G[u][i]); path.push_back(G[u][i]+1); } } void print_answer() { for(int i = 0; i < n; i++) { G[i].clear(); vis[i].clear(); } for(int i = 0; i < m; i++) { bool rev = false; if(!directed[i] && g.edges[id[i]].flow > 0) rev = true; if(!rev) { G[u[i]].push_back(v[i]); vis[u[i]].push_back(0); } else { G[v[i]].push_back(u[i]); vis[v[i]].push_back(0); } } path.clear(); euler(0); printf("1"); for(int i = path.size()-1; i >= 0; i--) printf(" %d", path[i]); printf("\n"); } int main(){ //READ; //WRITE; Di(T); while(T--){ in2(n,m); g.init(n+2); me(diff); for(int i=0;i<m;i++){ char s[5]; scanf("%d%d%s",&u[i],&v[i],s); u[i]--;v[i]--; directed[i]=(s[0]=='D'?1:0); diff[u[i]]++; diff[v[i]]--; if(!directed[i]){ id[i] = g.edges.size(); g.AddEdge(u[i],v[i],1); } } bool ok=true; for(int i=0;i<n;i++) if(diff[i]%2) { ok=false; break; } int s = n, t = n+1; if(ok) { int sum = 0; for(int i = 0; i < n; i++) { if(diff[i] > 0) { g.AddEdge(s, i, diff[i]/2); // provide "out-degree" sum += diff[i]/2; } if(diff[i] < 0) { g.AddEdge(i, t, -diff[i]/2); } } if(g.Maxflow(s, t) != sum) ok = false; } if(!ok) pf("No euler circuit exist\n"); else print_answer(); if(T) puts(""); } }