poj -- 1637 Sightseeing tour(混合图欧拉回路)
来源:互联网 发布:怪物弹珠淘宝 编辑:程序博客网 时间:2024/05/01 12:11
给一个n个顶点,m条边(既有有向边又有无向边)。求图中是否存在欧拉回路。
http://poj.org/problem?id=1637
用最大流求解。
把该图的无向边随便定向,计算每个点的入度和出度。如果有某个点出入度之差为奇数,那么肯定不存在欧拉回路。因为欧拉回路要求每点入度 = 出度,也就是总度数为偶数,存在奇数度点必不能有欧拉回路。
现在每个点入度和出度之差均为偶数。将这个偶数除以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连接的点,自然早在开始就已经满足入 = 出了。那么在网络流过程中,这些点属于“中间点”。我们知道中间点流量不允许有累积的,这样,进去多少就出来多少,反向之后,自然仍保持平衡。
所以,就这样,混合图欧拉回路问题,解了。
//#pragma comment(linker,"/STACK:1024000000,1024000000")#include <map>#include <set>#include <cmath>#include <queue>#include <stack>#include <cstdio>#include <string>#include <vector>#include <cstring>#include <iostream>#include <algorithm>using namespace std;typedef long long ll;typedef pair<int, int> PII;#define pb push_back#define MP make_pair#define lson l, m, rt << 1#define rson m + 1, r, rt << 1 | 1const double eps = 1e-6;const int inf = 0x3f3f3f3f;const int mod = 1000000007;const int maxn = 500000 + 10;///init是初始化要在加边之前初始化,然后调用max_flow(顶点数,边数,源点, 汇点)const int maxv = 200 + 10;///顶点个数const int maxe = 10000 + 10;///边数struct node{ int v, cap, next;}edge[maxe];int head[maxv], cnt;int n, m;///n是节点个数,m是边数int st, ed;///st是源点,ed是汇点int gap[maxv], h[maxv], d[maxv];void addedge(int u, int v, int w){///有向图加边 edge[cnt].v = v; edge[cnt].cap = w; edge[cnt].next = head[u]; head[u] = cnt++;///正向边 edge[cnt].v = u; edge[cnt].cap = 0; edge[cnt].next = head[v]; head[v] = cnt++;///反向边}int dfs(int x, int cost){ if(x == ed) return cost; ///当前节点是汇点,直接返回cost int can = cost, d, minh = n - 1; for(int i=head[x]; ~i; i=edge[i].next){ int v = edge[i].v, w = edge[i].cap; if(w > 0){///如果这条边的容量大于0 if(h[v] + 1 == h[x]){///如果这是允许弧 if(can > w) d = w;///如果当前弧的容量小于之前可增广的容量 else d = can; d = dfs(v, d);///从v开始可增广的容量为d ///更新弧的容量和可增广的容量 edge[i].cap -= d; edge[i ^ 1].cap += d; can -= d; if(h[st] >= n) return cost - can; if(!can) break;///不能再继续增广 } if(h[v] < minh) minh = h[v];///更新最小标号 } } if(can == cost){///如果没有增广...GAP gap[h[x]]--; if(gap[h[x]] == 0) h[st] = n;///存在断层,没有增广路了 h[x] = minh + 1;///重新标记,保证下次再访问的时候有流量 gap[h[x]]++; } return cost - can;///在这个点之前可以增广的 - 访问这个点之后可以增广的 = 在这个点增广的容量}int max_flow(int N, int M, int source, int sink){///SAP+GAP优化 n = N; m = M; st = source; ed = sink; gap[0] = n;///初始有n个节点标号为0 int ret = 0; while(h[st] < n){ ret += dfs(st, inf); } return ret;}void init(){ memset(head, -1, sizeof(head)); cnt = 0; memset(h, 0, sizeof(h));///h[i]表示i节点的标号 memset(gap, 0, sizeof(gap));///gap[i]表示标号为i的节点个数}int in[maxv], out[maxv];int T, N, M;int main(){ scanf("%d", &T); while(T--){ scanf("%d%d", &N, &M); init(); memset(in, 0, sizeof(in)); memset(out, 0, sizeof(out)); int sum = 0, x, bian = 0; for(int i=0; i<M; i++){ int u, v, w; scanf("%d%d%d", &u, &v, &w); if(w == 0)addedge(u, v, 1), bian++; in[v]++; out[u]++; } bool flag = true; for(int i=1; i<=N; i++){ x = abs(in[i] - out[i]); if(x & 1) {flag = false; break;} if(in[i] > out[i]) addedge(i, N + 1, x / 2), bian++, sum += x / 2; else if(out[i] > in[i]) addedge(0, i, x / 2), bian++; } if(flag && sum == max_flow(N + 2, bian, 0, N + 1)) puts("possible"); else puts("impossible"); } return 0;}
顺便。。。。
若有向图G存在欧拉回路,则G联通,对于所有顶点入度 = 出度。
若无向图G存在欧拉回路,则G联通,所有顶点度为偶数。
- POJ 1637 Sightseeing tour (混合图欧拉回路)
- poj 1637 Sightseeing tour(混合图欧拉回路)
- poj -- 1637 Sightseeing tour(混合图欧拉回路)
- [POJ 1637]Sightseeing tour[混合图欧拉回路]
- POJ 1637:Sightseeing tour 混合图欧拉回路
- 【POJ 1637】Sightseeing tour 混合图欧拉回路 最大流
- hdu 1956 || poj 1637 Sightseeing tour (混合图欧拉回路)
- POJ 1637 Sightseeing tour (混合图欧拉回路,网络最大流)
- POJ 1637 Sightseeing tour (混合图欧拉回路)
- 【最大流+混合图欧拉回路】POJ-1637 Sightseeing tour
- POJ 1637 Sightseeing tour 混合图欧拉回路 最大流
- poj 1637 Sightseeing tour 混迹图欧拉回路
- POJ 1637 Sightseeing tour (混合图的欧拉回路)
- poj 1637 Sightseeing tour(混合欧拉回路)
- poj 1637 Sightseeing tour(混合欧拉回路)
- POJ 1637 Sightseeing tour(混合欧拉回路,网络流)
- POJ 1637 Sightseeing tour 混合欧拉回路
- POJ 1637 Sightseeing tour(混合图的欧拉回路)
- Ubuntu 12.04使用cntlm配置代理上网
- 58464
- iOS多线程的初步研究(五)-- 如何让NSURLConnection在子线程中运行
- Spring的JavaMail实现异步发送邮件
- Android权限设置(AndroidManifest.xml)
- poj -- 1637 Sightseeing tour(混合图欧拉回路)
- 父页面和iframe页面之间方法的互相调用
- iOS多线程的初步研究(六)-- NSOperation
- IOS开发者常用的10个Xcode插件
- MySQL:讨人喜欢的 MySQL replace into 用法(insert into 的增强版)
- Unity Shader Matrix[Matrix]
- java toString()方法
- 转圈圈定制加载中视图
- Android TextView SpannableString样式详解