UVA-10735 - Euler Circuit(混合欧拉回路输出)
题意:给你一个图,有N个点,M条边,这M条边有的是单向的,有的是双向的.
问你能否找出一条欧拉回路,使得每条边都只经过一次!
分析:
下面转自别人的题解:
把该图的无向边随便定向,然后计算每个点的入度和出度。如果有某个点出入度之差为奇数,那么肯定不存在欧拉回路。因为欧拉回路要求每点入度 = 出度,也就是总度数为偶数,存在奇数度点必不能有欧拉回路。
好了,现在每个点入度和出度之差均为偶数。那么将这个偶数除以2,得x。也就是说,对于每一个点,只要将x条边改变方向(入>出就是变入,出>入就是变出),就能保证出 = 入。如果每个点都是出 = 入,那么很明显,该图就存在欧拉回路。
现在的问题就变成了:我该改变哪些边,可以让每个点出 = 入?构造网络流模型。首先,有向边是不能改变方向的,要之无用,删。一开始不是把无向边定向了吗?定的是什么向,就把网络构建成什么样,边长容量上限1。另新建s和t。对于入 > 出的点u,连接边(u, t)、容量为x,对于出 > 入的点v,连接边(s, v),容量为x(注意对不同的点x不同)。之后,察看是否有满流的分配。有就是能有欧拉回路,没有就是没有。欧拉回路是哪个?察看流值分配,将所有流量非 0(上限是1,流值不是0就是1)的边反向,就能得到每点入度 = 出度的欧拉图。
由于是满流,所以每个入 > 出的点,都有x条边进来,将这些进来的边反向,OK,入 = 出了。对于出 > 入的点亦然。那么,没和s、t连接的点怎么办?和s连接的条件是出 > 入,和t连接的条件是入 > 出,那么这个既没和s也没和t连接的点,自然早在开始就已经满足入 = 出了。那么在网络流过程中,这些点属于“中间点”。我们知道中间点流量不允许有累积的,这样,进去多少就出来多少,反向之后,自然仍保持平衡。
所以,就这样,混合图欧拉回路问题,解了。
// File Name: 10735.cpp // Author: Zlbing // Created Time: 2013/6/18 21:46:23 #include<iostream> #include<string> #include<algorithm> #include<cstdlib> #include<cstdio> #include<set> #include<map> #include<vector> #include<cstring> #include<stack> #include<cmath> #include<queue> using namespace std; #define CL(x,v); memset(x,v,sizeof(x)); #define INF 0x3f3f3f3f #define LL long long #define REP(i,r,n) for(int i=r;i<=n;i++) #define RREP(i,n,r) for(int i=n;i>=r;i--) const int MAXN=125; int n,m; struct Edge2{ int from,to; }; vector<Edge2> edges2; vector<int> G2[MAXN]; struct Edge{ int from,to,cap,flow; }; bool cmp(const Edge& a,const Edge& b){ return a.from < b.from || (a.from == b.from && a.to < b.to); } struct Dinic{ int n,m,s,t; vector<Edge> edges; vector<int> G[MAXN]; bool vis[MAXN]; int d[MAXN]; int cur[MAXN]; void init(int n){ this->n=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});//当是无向图时,反向边容量也是cap,有向边时,反向边容量是0 m=edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } bool BFS(){ CL(vis,0); queue<int> Q; Q.push(s); d[s]=0; vis[s]=1; 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(!vis[e.to]&&e.cap>e.flow){ vis[e.to]=1; d[e.to]=d[x]+1; Q.push(e.to); } } } return vis[t]; } int DFS(int x,int a){ if(x==t||a==0)return a; int flow=0,f; for(int& i=cur[x];i<G[x].size();i++){ Edge& e=edges[G[x][i]]; if(d[x]+1==d[e.to]&&(f=DFS(e.to,min(a,e.cap-e.flow)))>0){ e.flow+=f; edges[G[x][i]^1].flow-=f; flow+=f; a-=f; if(a==0)break; } } return flow; } //当所求流量大于need时就退出,降低时间 int Maxflow(int s,int t,int need){ this->s=s;this->t=t; int flow=0; while(BFS()){ CL(cur,0); flow+=DFS(s,INF); if(flow>need)return flow; } return flow; } //最小割割边 vector<int> Mincut(){ BFS(); vector<int> ans; for(int i=0;i<edges.size();i++){ Edge& e=edges[i]; if(vis[e.from]&&!vis[e.to]&&e.cap>0)ans.push_back(i); } return ans; } void Reduce(){ for(int i = 0; i < edges.size(); i++) edges[i].cap -= edges[i].flow; } void ClearFlow(){ for(int i = 0; i < edges.size(); i++) edges[i].flow = 0; } }; Dinic solver; int in[MAXN],out[MAXN]; stack<int> S; int vis[MAXN*MAXN]; void build() { for(int i=0;i<solver.edges.size();i++) { Edge e=solver.edges[i]; if(e.from>=1&&e.from<=n&&e.to>=1&&e.to<=n&&e.cap>0) { if(e.flow) { edges2.push_back((Edge2){e.to,e.from}); int mm=edges2.size(); G2[e.to].push_back(mm-1); } else { edges2.push_back((Edge2){e.from,e.to}); int mm=edges2.size(); G2[e.from].push_back(mm-1); } } } } void dfs(int u) { //printf("u=%d \n",u); for(int i=0;i<G2[u].size();i++) { int mm=G2[u][i]; Edge2 e=edges2[mm]; int v=e.to; //printf("aau=%d v=%d\n",u,v); if(!vis[mm]) { //printf("u=%d v=%d\n",u,v); vis[mm]=1; dfs(v); } } S.push(u); } int main() { int T; scanf("%d",&T); for(int cas=1;cas<=T;cas++) { scanf("%d%d",&n,&m); solver.init(n+2); int s=0,t=n+1; for(int i=0;i<=n;i++)G2[i].clear(); edges2.clear(); CL(in,0); CL(out,0); int a,b;char c[10]; for(int i=0;i<m;i++) { scanf("%d%d%s",&a,&b,c); if(c[0]=='D'){ edges2.push_back((Edge2){a,b}); int mm=edges2.size(); G2[a].push_back(mm-1); in[b]++;out[a]++; } else if(c[0]=='U') { solver.AddEdge(a,b,1); in[b]++;out[a]++; } } bool flag=true; for(int i=1;i<=n;i++) if(abs(in[i]-out[i])&1) { flag=false;break; } if(!flag) { printf("No euler circuit exist\n"); if(cas!=T)printf("\n"); continue; } int sum=0; for(int i=1;i<=n;i++) { if(in[i]>out[i]) { solver.AddEdge(i,t,(in[i]-out[i])/2); } else if(out[i]>in[i]) { solver.AddEdge(s,i,(out[i]-in[i])/2); sum+=abs(in[i]-out[i])/2; } } // for(int i=0;i<solver.edges.size();i++) // { // printf("u==%d v==%d cap=%d\n",solver.edges[i].from,solver.edges[i].to,solver.edges[i].cap); // } if(sum!=solver.Maxflow(s,t,INF)) { printf("No euler circuit exist\n"); if(cas!=T)printf("\n"); continue; } build(); //for(int i=0;i<edges2.size();i++) //printf("from=%d to=%d\n",edges2[i].from,edges2[i].to); while(!S.empty())S.pop(); CL(vis,0); dfs(1); int first=0; while(!S.empty()) { if(first) printf(" "); first++; printf("%d",S.top()); S.pop(); } printf("\n"); if(cas!=T)printf("\n"); } return 0; }