题目链接
题目大概意思就是给出V个顶点E条边,边可以是有向边也可以是无向边,给定一个混合网络,求一条欧回路
紫书上的思路大概意思:将无向边定向,比如u->v的边本来无向,现在我们假设是u->v是有向的,然后在另一个图G1连接一条u->v的有向边
接下来检查每个点的入读和出度,在欧拉回路中入读和出度囧性不一样无解,如果入读不等于出度则可能通过将一天出边改成入边来达到入读等于出度的目的
如果要将入边改成出边,则需要翻转边的操作,例如u->v翻转成v->u,则u的出度-1入度+1,v的出度+1入度-1,每次翻转对应一个顶点的入度+1或-1,出度+1或-1,这种传递顶点度的网络流,只要使得传递的度等于最大流,问题就有解(每个点的度去了他该去的地方使得形成欧拉回路)。
贴上LRJ的代码学习建图过程
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn=100+10;
const int maxm=500+10;
const int inf=1000000000;
struct Edge{
int from,to,cap,flow;
Edge(int a,int b,int c,int d):from(a),to(b),cap(c),flow(d){}
};
struct Dinic{
int n,m,s,t;
vector<int> G[maxn];
vector<Edge> edges;
int d[maxn],p[maxn];
bool vis[maxn];
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);
}
bool bfs(){
memset(vis,0,sizeof(vis));
queue<int> q;
q.push(s);
d[s]=0;
vis[s]=1;
while(!q.empty()){
int u=q.front();q.pop();
for(int i=0;i<G[u].size();i++){
Edge& e=edges[G[u][i]];
if(!vis[e.to]&&e.cap>e.flow){
vis[e.to]=1;
d[e.to]=d[u]+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=p[x];i<G[x].size();i++){
Edge& e=edges[G[x][i]];
if(d[e.to]==d[x]+1&&(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;
}
int Maxflow(int s,int t){
this->s=s;
this->t=t;
int flow=0;
while(bfs()){
memset(p,0,sizeof(p));
flow+=dfs(s,inf);
}
return flow;
}
};
Dinic g;
int n,m,u[maxm],v[maxm],directed[maxm],id[maxm],diff[maxm];
//for Euler tuor only
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(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
g.init(n+2);
memset(diff,0,sizeof(diff));
for(int i=0;i<m;i++){
char dir[9];
scanf("%d%d%s",&u[i],&v[i],dir);
u[i]--;v[i]--;
directed[i]=(dir[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!=0){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);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)printf("No euler circuit exist\n");
else print_answer();
}
return 0;
}