UVA 10735 最大流 混合欧拉回路 输出路径

UVA 10735 最大流 混合欧拉回路 输出路径

分类: UVa && LA 图论   125人阅读  评论(0)  收藏  举报

题意:

给你一个图,有N个点,M条边,有单向边和双向边

让你是否存在欧拉回路,有就输出路径


1.判断是否有欧拉回路: 可以用最大流来判断

首先,我们从结论出发: 存在欧拉回路的充要条件是    每个点的入度等于出度。

先把所用无向边随便定向(我们就按输入的时候的方向定向),

问题就转化成  “改变其中一些无向边的方向,使所有的点入度等于出度”。

对于改变某一条无向边, 这条边所在的点的度数改变2(可能-2, 可能+2)。

所以有如果有某个点出入度之差为奇数,那么肯定不存在欧拉回路(情况1)


记出入度之差为d

接下来讨论除情况1以外的情况:

现在,每个点入度和出度之差均为偶数。

对于每个点,我们需要改变跟该点相连的x/2条边, 就可以使该点的入度等于出度

新建源点S和汇点T

对于d < 0 的点i, 连S---->i , 流量为-d

对于d > 0 的点i, 连i----->T,流量为d

对于每条无向边<i,j> ,连i----->j, 流量为2   

流一遍最大流,如果对于所有的点i,存在S----->i的边并且漫流,那么欧拉回路就有解。



2.输出欧拉回路: dfs+栈保存

通过最大流以后,我们检查无向边<i,j> 流过的流量,我们可以确定无向边<i,j> 的方向

然后问题就变为  "输出无向图的欧拉回路"。


我们用dfs搜索,访问每条边,对于节点u,当其u以下的儿子节点都搜过时,我们把u入栈

把栈反向输出,就是我们要的欧拉回路。


[cpp]  view plain copy
  1. #include <cstdio>  
  2. #include <cstring>  
  3. #include <algorithm>  
  4. #include <vector>  
  5. #include <stack>  
  6. using namespace std;  
  7. #define PII pair<int, int>  
  8. #define MP make_pair  
  9. #define X first  
  10. #define Y second  
  11. const int maxn = 510;  
  12. const int inf = 1e9;  
  13. struct Edge {  
  14.     int v, next, c, op;  
  15. } edge[maxn * maxn << 1];  
  16.   
  17. int E, head[maxn];  
  18. int n, m;  
  19. int S, T;  
  20.   
  21. vector<PII> edges[maxn];  
  22. void add(int s, int t, int c) {  
  23.     edge[E].v = t;  
  24.     edge[E].c = c;  
  25.     edge[E].op = 1;  
  26.     edge[E].next = head[s];  
  27.     head[s] = E++;  
  28.     edge[E].v = s;  
  29.     edge[E].c = 0;  
  30.     edge[E].op = 0;  
  31.     edge[E].next = head[t];  
  32.     head[t] = E++;  
  33. }  
  34. int st[maxn], top;  
  35. void init() {  
  36.     E = 0;  
  37.     memset(head, -1, sizeof(head));  
  38. }  
  39.   
  40. int gap[maxn], dis[maxn], pre[maxn], cur[maxn];  
  41. int sap(int s, int t, int n) // s 源点,t汇点,n顶点总数  
  42.         {  
  43.     int i;  
  44.     for(i = 0; i <= n; i++) {  
  45.         dis[i] = gap[i] = 0;  
  46.         cur[i] = head[i];  
  47.     }  
  48.     gap[0] = n;  
  49.     int u = pre[s] = s, maxf = 0, aug = inf, v;  
  50.     while(dis[s] < n) {  
  51.         loop: for(i = cur[u]; i != -1; i = edge[i].next) {  
  52.             v = edge[i].v;  
  53.             if(edge[i].c > 0 && dis[u] == dis[v] + 1) {  
  54.                 aug = min(aug, edge[i].c);  
  55.                 pre[v] = u;  
  56.                 cur[u] = i;  
  57.                 u = v;  
  58.                 if(u == t) {  
  59.                     while(u != s) {  
  60.                         u = pre[u];  
  61.                         edge[cur[u]].c -= aug;  
  62.                         edge[cur[u] ^ 1].c += aug;  
  63.                     }  
  64.                     maxf += aug;  
  65.                     aug = inf;  
  66.                 }  
  67.                 goto loop;  
  68.             }  
  69.         }  
  70.         int min_d = n;  
  71.         for(i = head[u]; i != -1; i = edge[i].next) {  
  72.             v = edge[i].v;  
  73.             if(edge[i].c > 0 && dis[v] < min_d) {  
  74.                 min_d = dis[v];  
  75.                 cur[u] = i;  
  76.             }  
  77.         }  
  78.         if(!(--gap[dis[u]]))  
  79.             break;  
  80.         ++gap[dis[u] = min_d + 1];  
  81.         u = pre[u];  
  82.     }  
  83.     return maxf;  
  84. }  
  85. char buf[3];  
  86. int d[103];  
  87. int x, y;  
  88. bool vis[maxn];  
  89. void dfs(int u) {  
  90.     int i;  
  91.     for (i = 0; i < (int) edges[u].size(); i++) {  
  92.         int v = edges[u][i].X;  
  93.         int id = edges[u][i].Y;  
  94.         if (vis[id])  
  95.             continue;  
  96.         vis[id] = 1;  
  97.         dfs(v);  
  98.     }  
  99.     st[top++] = u + 1;  
  100. }  
  101.   
  102. int id;  
  103. int main() {  
  104.     int i, j, cas;  
  105.     scanf("%d", &cas);  
  106.     while (cas--) {  
  107.         init();  
  108.         scanf("%d%d", &n, &m);  
  109.         for (i = 0; i < n; i++) {  
  110.             d[i] = 0;  
  111.             edges[i].clear();  
  112.         }  
  113.         top = 0;  
  114.         memset(vis, 0, sizeof(vis));  
  115.         id = 0;  
  116.         for (i = 0; i < m; i++) {  
  117.             scanf("%d%d%s", &x, &y, buf);  
  118.             d[--x]--;  
  119.             d[--y]++;  
  120.             if (buf[0] == 'U') {  
  121.                 add(x, y, 2);  
  122.             } else {  
  123.                 edges[x].push_back(MP(y, id++));  
  124.             }  
  125.         }  
  126.   
  127.         for (i = 0; i < n; i++)  
  128.             if (d[i] & 1)  
  129.                 break;  
  130.         if (i != n) {  
  131.             puts("No euler circuit exist\n");  
  132.             continue;  
  133.         }  
  134.         S = n;  
  135.         T = n + 1;  
  136.         for (i = 0; i < n; i++) {  
  137.             if (d[i] < 0)  
  138.                 add(S, i, -d[i]);  
  139.             else if (d[i] > 0)  
  140.                 add(i, T, d[i]);  
  141.         }  
  142.         int sum = sap(S, T, T + 1);  
  143.         for (i = head[S]; ~i; i = edge[i].next)  
  144.             if (edge[i].c)  
  145.                 break;  
  146.         if (~i) {  
  147.             puts("No euler circuit exist\n");  
  148.             continue;  
  149.         }  
  150.   
  151.         for (i = 0; i < n; i++)  
  152.             for (j = head[i]; ~j; j = edge[j].next)  
  153.                 if (edge[j].op) {  
  154.                     int v = edge[j].v;  
  155.                     if (v >= n)  
  156.                         continue;  
  157.                     if (edge[j ^ 1].c) {  
  158.                         edges[v].push_back(MP(i, id++));  
  159.   
  160.                     } else  
  161.                         edges[i].push_back(MP(v, id++));  
  162.                 }  
  163.   
  164.         dfs(0);  
  165.         for (i = top - 1; i >= 1; i--)  
  166.             printf("%d ", st[i]);  
  167.         printf("%d\n\n", st[0]);  
  168.   
  169.     }  
  170.     return 0;  
  171. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值