POJ 1637 Sightseeing tour (混合圖歐拉路判定)


Sightseeing tour
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 6986   Accepted: 2901

Description

The city executive board in Lund wants to construct a sightseeing tour by bus in Lund, so that tourists can see every corner of the beautiful city. They want to construct the tour so that every street in the city is visited exactly once. The bus should also start and end at the same junction. As in any city, the streets are either one-way or two-way, traffic rules that must be obeyed by the tour bus. Help the executive board and determine if it's possible to construct a sightseeing tour under these constraints.

Input

On the first line of the input is a single positive integer n, telling the number of test scenarios to follow. Each scenario begins with a line containing two positive integers m and s, 1 <= m <= 200,1 <= s <= 1000 being the number of junctions and streets, respectively. The following s lines contain the streets. Each street is described with three integers, xi, yi, and di, 1 <= xi,yi <= m, 0 <= di <= 1, where xi and yi are the junctions connected by a street. If di=1, then the street is a one-way street (going from xi to yi), otherwise it's a two-way street. You may assume that there exists a junction from where all other junctions can be reached.

Output

For each scenario, output one line containing the text "possible" or "impossible", whether or not it's possible to construct a sightseeing tour.

Sample Input

4
5 8
2 1 0
1 3 0
4 1 1
1 5 0
5 4 1
3 4 0
4 2 1
2 2 0
4 4
1 2 1
2 3 0
3 4 0
1 4 1
3 3
1 2 0
2 3 0
3 2 0
3 4
1 2 0
2 3 1
1 2 0
3 2 0

Sample Output

possible
impossible
impossible
possible

Source

 

題目鏈接:

http://poj.org/problem?id=1637

 

就是對有無向邊和有向邊的混合圖,判斷存不存在歐拉回路。

 

參考下面的解釋:

 

【混合圖】
混合圖(既有有向邊又有無向邊的圖)中歐拉環、歐拉路徑的判定需要借助網絡流!

(1)歐拉環的判定:
一開始當然是判斷原圖的基圖是否連通,若不連通則一定不存在歐拉環或歐拉路徑(不考慮度數為0的點)。

其實,難點在於圖中的無向邊,需要對所有的無向邊定向(指定一個方向,使之變為有向邊),使整個圖變成一個有向歐拉圖(或有向半歐拉圖)。若存在一個定向滿足此條件,則原圖是歐拉圖(或半歐拉圖)否則不是。關鍵就是如何定向?

首先給原圖中的每條無向邊隨便指定一個方向(稱為初始定向),將原圖改為有向圖G',然后的任務就是改變G'中某些邊的方向(當然是無向邊轉化來的,原混合圖中的有向邊不能動)使其滿足每個點的入度等於出度。
設D[i]為G'中(點i的出度 - 點i的入度)。可以發現,在改變G'中邊的方向的過程中,任何點的D值的奇偶性都不會發生改變(設將邊<i, j>改為<j, i>,則i入度加1出度減1,j入度減1出度加1,兩者之差加2或減2,奇偶性不變)!而最終要求的是每個點的入度等於出度,即每個點的D值都為0,是偶數,故可得:若初始定向得到的G'中任意一個點的D值是奇數,那么原圖中一定不存在歐拉環!

若初始D值都是偶數,則將G'改裝成網絡:設立源點S和匯點T,對於每個D[i]>0的點i,連邊<S, i>,容量為D[i]/2;對於每個D[j]<0的點j,連邊<j, T>,容量為-D[j]/2;G'中的每條邊在網絡中仍保留,容量為1(表示該邊最多只能被改變方向一次)。求這個網絡的最大流,若S引出的所有邊均滿流,則原混合圖是歐拉圖,將網絡中所有流量為1的中間邊(就是不與S或T關聯的邊)在G'中改變方向,形成的新圖G''一定是有向歐拉圖;若S引出的邊中有的沒有滿流,則原混合圖不是歐拉圖。

為什么能這樣建圖?
考慮網絡中的一條增廣路徑S-->i-->...-->j-->T,將這條從i到j的路徑在G'中全部反向,則:i的入度加1出度減1,j的入度減1出度加1,路徑中其它點的入度出度均不變。而i是和S相連的,因此初始D[i]>0,即i的出度大於入度,故這樣反向之后D[i]減少2;同理,j是和T相連的,這樣反向之后D[j]增加2。因此,若最大流中邊<S, i>滿流(流量為初始D[i]/2),此時D[i]值就變成了0,也就是i的入度等於出度。因此只要使所有S引出的邊全部滿流,所有初始D值>0的點的D值將等於0,又因為將邊變向后所有點的D值之和不變,所有初始D值小於0的點的D值也將等於0,而初始D值等於0的D點既不與S相連也不與T相連,所以它們是網絡中的中間點,而中間點的流入量等於流出量,故它們的入度和出度一直不變,即D值一直為0。因此,整個圖G'成為歐拉圖。

(2)歐拉路徑的判定:
首先可以想到的是枚舉歐拉路徑的起點i和終點j,然后在圖中添加邊<j, i>,再求圖中是否有歐拉回路即可。但是,該算法的時間復雜度達到了O(M * 最大流的時間),需要優化。
前面已經說過,在將邊變向的過程中任何點的D值的奇偶性都不會改變,而一個有向圖有歐拉路徑的充要條件是基圖連通且有且只有一個點的入度比出度少1(作為歐拉路徑的起點),有且只有一個點的入度比出度多1(作為終點),其余點的入度等於出度。這就說明,先把圖中的無向邊隨便定向,然后求每個點的D值,若有且只有兩個點的初始D值為奇數,其余的點初始D值都為偶數,則有可能存在歐拉路徑(否則不可能存在)。進一步,檢查這兩個初始D值為奇數的點,設為點i和點j,若有D[i]>0且D[j]<0,則i作起點j作終點(否則若D[i]與D[j]同號則不存在歐拉路徑),連邊<j, i>,求是否存在歐拉環即可(將求出的歐拉環中刪去邊<j, i>即可)。這樣只需求一次最大流。

 

 

就是轉化成最大流,最一次最大流,看是不是滿流

 

 

 

  1 /* ***********************************************
  2 Author        :kuangbin
  3 Created Time  :2014-2-3 11:26:49
  4 File Name     :E:\2014ACM\專題學習\圖論\歐拉路\混合圖\POJ1637.cpp
  5 ************************************************ */
  6 
  7 #include <stdio.h>
  8 #include <string.h>
  9 #include <iostream>
 10 #include <algorithm>
 11 #include <vector>
 12 #include <queue>
 13 #include <set>
 14 #include <map>
 15 #include <string>
 16 #include <math.h>
 17 #include <stdlib.h>
 18 #include <time.h>
 19 using namespace std;
 20 
 21 const int MAXN = 210;
 22 //最大流ISAP部分
 23 const int MAXM = 20100;
 24 const int INF = 0x3f3f3f3f;
 25 struct Edge
 26 {
 27     int to,next,cap,flow;
 28 }edge[MAXM];
 29 int tol;
 30 int head[MAXN];
 31 int gap[MAXN],dep[MAXN],pre[MAXN],cur[MAXN];
 32 void init()
 33 {
 34     tol = 0;
 35     memset(head,-1,sizeof(head));
 36 }
 37 void addedge(int u,int v,int w,int rw = 0)
 38 {
 39     edge[tol].to = v;
 40     edge[tol].cap = w;
 41     edge[tol].next = head[u];
 42     edge[tol].flow = 0;
 43     head[u] = tol++;
 44     edge[tol].to = u;
 45     edge[tol].cap = rw;
 46     edge[tol].next = head[v];
 47     edge[tol].flow = 0;
 48     head[v] = tol++;
 49 }
 50 int sap(int start,int end,int N)
 51 {
 52     memset(gap,0,sizeof(gap));
 53     memset(dep,0,sizeof(dep));
 54     memcpy(cur,head,sizeof(head));
 55     int u = start;
 56     pre[u] = -1;
 57     gap[0] = N;
 58     int ans = 0;
 59     while(dep[start] < N)
 60     {
 61         if(u == end)
 62         {
 63             int Min = INF;
 64             for(int i = pre[u]; i != -1;i = pre[edge[i^1].to])
 65                 if(Min > edge[i].cap - edge[i].flow)
 66                     Min = edge[i].cap - edge[i].flow;
 67             for(int i = pre[u];i != -1;i = pre[edge[i^1].to])
 68             {
 69                 edge[i].flow += Min;
 70                 edge[i^1].flow -= Min;
 71             }
 72             u = start;
 73             ans += Min;
 74             continue;
 75         }
 76         bool flag = false;
 77         int v;
 78         for(int i = cur[u];i != -1;i = edge[i].next)
 79         {
 80             v = edge[i].to;
 81             if(edge[i].cap - edge[i].flow && dep[v] + 1 == dep[u])
 82             {
 83                 flag = true;
 84                 cur[u] = pre[v] = i;
 85                 break;
 86             }
 87         }
 88         if(flag)
 89         {
 90             u = v;
 91             continue;
 92         }
 93         int Min = N;
 94         for(int i = head[u];i != -1;i = edge[i].next)
 95             if(edge[i].cap - edge[i].flow && dep[edge[i].to] < Min)
 96             {
 97                 Min = dep[edge[i].to];
 98                 cur[u] = i;
 99             }
100         gap[dep[u]]--;
101         if(!gap[dep[u]])return ans;
102         dep[u] = Min+1;
103         gap[dep[u]]++;
104         if(u != start)u = edge[pre[u]^1].to;
105     }
106     return ans;
107 }
108 //the end of 最大流部分
109 
110 int in[MAXN],out[MAXN];//每個點的出度和入度
111 
112 int main()
113 {
114     //freopen("in.txt","r",stdin);
115     //freopen("out.txt","w",stdout);
116     int T;
117     int n,m;
118     scanf("%d",&T);
119     while(T--)
120     {
121         scanf("%d%d",&n,&m);
122         init();
123         int u,v,w;
124         memset(in,0,sizeof(in));
125         memset(out,0,sizeof(out));
126         while(m--)
127         {
128             scanf("%d%d%d",&u,&v,&w);
129             out[u]++; in[v]++;
130             if(w == 0)//雙向
131                 addedge(u,v,1);
132         }
133         bool flag = true;
134         for(int i = 1;i <= n;i++)
135         {
136             if(out[i] - in[i] > 0)
137                 addedge(0,i,(out[i] - in[i])/2);
138             else if(in[i] - out[i] > 0)
139                 addedge(i,n+1,(in[i] - out[i])/2);
140             if((out[i] - in[i]) & 1)
141                 flag = false;
142         }
143         if(!flag)
144         {
145             printf("impossible\n");
146             continue;
147         }
148         sap(0,n+1,n+2);
149         for(int i = head[0]; i != -1;i = edge[i].next)
150             if(edge[i].cap > 0 && edge[i].cap > edge[i].flow)
151             {
152                 flag = false;
153                 break;
154             }
155         if(flag)printf("possible\n");
156         else printf("impossible\n");
157     }
158     return 0;
159 }

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM