POJ 1637 Sightseeing tour

这道题是第一道欧拉回路(混合图求欧拉回路)的题,还算比较顺利地过掉了。

1 定义

欧拉通路 (Euler tour)——通过图中每条边一次且仅一次,并且过每一顶点的通路。
欧拉回路 (Euler circuit)——通过图中每条边一次且仅一次,并且过每一顶点的回路。
欧拉图——存在欧拉回路的图。

2 无向图是否具有欧拉通路或回路的判定

G有欧拉通路的充分必要条件为:G 连通,G中只有两个奇度顶点(它们分别是欧拉通路的两个端点)。
G有欧拉回路(G为欧拉图):G连通,G中均为偶度顶点。

3 有向图是否具有欧拉通路或回路的判定

D有欧拉通路:D连通,除两个顶点外,其余顶点的入度均等于出度,这两个特殊的顶点中,一个顶点的入度比出度大1,另一个顶点的入度比出度小1。
D有欧拉回路(D为欧拉图):D连通,D中所有顶点的入度等于出度。

4 混合图。混合图也就是无向图与有向图的混合,即图中的边既有有向边也有无向边。

5 混合图欧拉回路

混合图欧拉回路用的是网络流。
把该图的无向边随便定向,计算每个点的入度和出度。如果有某个点出入度之差为奇数,那么肯定不存在欧拉回路。因为欧拉回路要求每点入度 = 出度,也就是总度数为偶数,存在奇数度点必不能有欧拉回路。
现在每个点入度和出度之差均为偶数。将这个偶数除以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连接的点,自然早在开始就已经满足入 = 出了。那么在网络流过程中,这些点属于“中间点”。我们知道中间点流量不允许有累积的,这样,进去多少就出来多少,反向之后,自然仍保持平衡。
所以,就这样,混合图欧拉回路问题,解了。

ContractedBlock.gif ExpandedBlockStart.gif Code
  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <algorithm>
  4 #define M(x, n) memset(x, n, sizeof(x))
  5 #define rep(i, n) for(int i = 0; i < n; ++i)
  6 
  7 using namespace std;
  8 
  9 const int inf = 0x7fffffff;
 10 const int MaxN = 2000;
 11 
 12 struct Edge {
 13     int u, v, w;
 14     struct Edge *next, *neg;
 15     Edge() {}
 16     Edge(const int &U, const int &V, const int &W)
 17         :u(U), v(V), w(W){}
 18 }mem[1<<19];
 19 
 20 Edge *adj[MaxN<<1], *pre[MaxN<<1];
 21 int src, dst, mtp;
 22 int q[MaxN<<1], qs, qe;
 23 int f[MaxN<<1], mark[MaxN<<1], cut[MaxN<<1];
 24 int m, s, indeg[MaxN], outdeg[MaxN];
 25 
 26 inline void addedge(const int &u, const int &v, const int &w) {
 27     mem[mtp] = Edge(u, v, w);
 28     mem[mtp].next = adj[u]; adj[u] = mem + mtp++;
 29     mem[mtp] = Edge(v, u, 0);
 30     mem[mtp].next = adj[v]; adj[v] = mem + mtp++;
 31     adj[u]->neg = adj[v]; adj[v]->neg = adj[u];
 32 }
 33 
 34 bool spfa(int src, int dst) {
 35     int u, v;
 36     M(f, 0); M(mark, 0); M(pre, 0);
 37     f[src] = inf; mark[src] = true; pre[src] = NULL;
 38     q[0= src; qs = 0; qe = 1;
 39     while(qs != qe) {
 40         u = q[qs++]; if(qs == MaxN) qs = 0;
 41         for(Edge *= adj[u]; p; p = p->next) {
 42             v = p->v;
 43             if(!mark[v] && p->> 0) {    //<<<<<<<<<<<<<<<<<<<<<<<
 44                 f[v] = min(f[u], p->w);
 45                 pre[v] = p;
 46                 mark[v] = true;
 47                 q[qe++= v; if(qe == MaxN) qe = 0;
 48             }
 49         }
 50     }
 51     if(f[dst] > 0)
 52         return true;
 53     return false;
 54 }
 55 
 56 int MaxFlow() {
 57     int flow = 0;
 58     while(spfa(src, dst)) {
 59         flow += f[dst];
 60         Edge *= pre[dst];
 61         for(int u; p; u = p->u, p = pre[u])
 62             p->-= f[dst], p->neg->+= f[dst];
 63     }
 64     return flow;
 65 }
 66 
 67 inline void add(int i, int &flow) {
 68     if(outdeg[i] > indeg[i]) {
 69         addedge(src, i, (outdeg[i]-indeg[i])/2);
 70         flow += (outdeg[i]-indeg[i])/2;
 71     }
 72     else if(outdeg[i] < indeg[i])
 73         addedge(i, dst, (indeg[i]-outdeg[i])/2);
 74 }
 75 
 76 int main() {
 77     int t;
 78     int bufu[MaxN], bufv[MaxN], bufm[MaxN];
 79     for(scanf("%d"&t); t--;) {
 80         scanf("%d%d"&m, &s);
 81         M(indeg, 0); M(outdeg, 0);
 82         for(int i = 0; i < s; ++i) {
 83             scanf("%d%d%d", bufu+i, bufv+i, bufm+i);
 84             outdeg[bufu[i]]++; indeg[bufv[i]]++;
 85         }
 86         int i;
 87         for(i = 1; i <= m; ++i) {
 88             if((outdeg[i] - indeg[i] + 1000)&1)
 89                 break;
 90         }
 91         if(i <= m) {
 92             printf("impossible\n"); continue;
 93         }
 94         src = 0; dst = m + 1;
 95         int Flow = 0;
 96         M(adj, 0); mtp = 0;
 97         for(int i = 0; i < s; ++i) {
 98             if(!bufm[i] && bufu[i] != bufv[i])
 99                 addedge(bufu[i], bufv[i], 1);
100         }
101         for(int i = 1; i <= m; ++i) 
102             add(i, Flow);
103         if(MaxFlow() == Flow)
104             printf("possible\n");
105         else
106             printf("impossible\n");
107     }
108     return 0;
109 }
110 

 

转载于:https://www.cnblogs.com/destinydesigner/archive/2009/09/28/1575674.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值