题意:
判断混合图中是否存在欧拉回路,如果存在欧拉回路,输出路径。
思路:
欧拉回路 存在每条边经过且只经过一次后回到原点的路径
在混合图中存在欧拉回路,需要满足以下条件:
1.把所有无向边任意规定一个方向后,对于每个点,满足 |入度-出度| % 2 == 0
2.按照上面已经规定的方向,利用 无向边 建图(有向边忽略掉),然后对于每个结点u,如果in[u]<out[u], 建边(s, u, |入度-出度| / 2);如果in[u]>out[u], 建边(u, t, |入度-出度| / 2)
括号中的内容分别是 (起点,终点,容量)
3.新建的图G‘中找最大流,如果满流就说明欧拉回路是存在的~
欧拉回路的输出我感觉挺难想的。。我太弱了吧.....T_T
就是把所有用到的边都存下来~(原图中的有向边必然要存下来),但是对于原图中的无向边,我们要根据刚才最大流时每条边中的流量关系来确定其方向:如果规定方向后,跑出最大流时这条无向边中有流量,说明要将这条边反向~
然后利用某个算法(见代码)~~来把欧拉回路找粗来。。。
code:
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<vector> #include<string> #include<queue> #include<map> #include<set> #include<cmath> #include<cstdlib> using namespace std; #define INF 0x3f3f3f3f #define PI acos(-1.0) #define mem(a, b) memset(a, b, sizeof(a)) typedef pair<int,int> pii; typedef long long LL; //------------------------------ const int maxn = 205; int n,m; struct Edge{ int to, cap, rev;//终点 容量 反向边 Edge(int to_ = 0, int cap_ = 0, int rev_ = 0){ to = to_; cap = cap_; rev = rev_; } }; vector<Edge> g[maxn], qg[maxn];//qg[maxn]是欧拉回路用到的边 int level[maxn];//顶点到源点的距离标号 int iter[maxn]; void add(int from, int to){//欧拉回路用到的边 Edge tmp1(to, 0, qg[to].size()); qg[from].push_back(tmp1); } void add_Edge(int from, int to, int cap){ Edge tmp1(to, cap, g[to].size()); g[from].push_back(tmp1); Edge tmp2(from, 0, g[from].size()-1); g[to].push_back(tmp2); } void bfs(int s){ memset(level, -1, sizeof(level)); queue<int> q; level[s] = 0; q.push(s); while(!q.empty()){ int v = q.front(); q.pop(); for(int i = 0; i < g[v].size(); i++){ Edge& e = g[v][i]; if(e.cap > 0 && level[e.to] < 0){ level[e.to] = level[v] + 1; q.push(e.to); } } } } int dfs(int v, int t, int f){ if(v == t) return f; for(int& i = iter[v]; i < g[v].size(); i++){ Edge& e = g[v][i]; if(e.cap > 0 && level[v] < level[e.to]){ int d = dfs(e.to, t, min(e.cap, f)); if(d > 0){ e.cap -= d; g[e.to][e.rev].cap += d; return d; } } } return 0; } int max_flow(int s, int t){ int flow = 0; for(;;){ bfs(s); if(level[t] < 0) return flow; memset(iter, 0, sizeof(iter)); int f; while((f = dfs(s, t, INF)) > 0){ flow += f; } } } //------------------上面是最大流模板部分 正确---------------------- int in[maxn], out[maxn]; int put[1000005]; int cnt = 0; void print(int u){ //打印欧拉回路 for(int i = 0; i < qg[u].size(); i++){ Edge& et = qg[u][i]; if(!et.cap){ et.cap = 1; print(et.to); } } put[cnt++] = u; } void init(){ memset(G, 0, sizeof(G)); memset(in, 0, sizeof(in)); memset(out, 0, sizeof(out)); for(int i = 0; i < maxn; i++) g[i].clear(); for(int i = 0; i < maxn; i++) qg[i].clear(); n = Scan(); m = Scan(); int u, v; char s[10]; for(int i = 1; i <= m; i++){ u = Scan(); v = Scan(); scanf("%s", s); if(s[0] == 'U'){ add_Edge(u, v, 1); } else { add(u, v); } out[u] ++; in[v] ++; } } void solve(){ for(int i = 1; i <= n; i++){ if(abs(out[i] - in[i]) % 2){ printf("No euler circuit exist\n"); return; } } int sumv = 0; for(int i = 1; i <= n; i++){ if(in[i] < out[i]){ add_Edge(0 , i, (out[i] - in[i]) / 2); sumv += (out[i] - in[i])/2; } else if(out[i] < in[i]){ add_Edge(i, n+1, (in[i] - out[i]) / 2); } } int ans = max_flow(0, n+1); if(ans != sumv){ printf("No euler circuit exist\n"); return; } for(int i = 1; i <= n; i++){ for(int j = 0; j < g[i].size(); j++){ Edge et = g[i][j]; int v = et.to; if(v == 0 || v == n+1 || !et.cap) continue; //建立了双向边,所以cap!=0的边说明其反向边中有流量,所以其实应该增加这条边 add(i, v); } } cnt = 0; print(1); for(int i = cnt - 1; ~i; --i) printf("%d%c", put[i], i ? ' ' : '\n'); } int main(){ int t; scanf("%d",&t); while(t--){ init(); solve(); if(t != 0) printf("\n"); } return 0; }
反正我判断是不是欧拉回路的时候用的时间很少的,我干囧好简单...但是我刚开始的时候并不会输出路径撒....sigh..
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-11-08 10:34:35