Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 6986 | Accepted: 2901 |
Description
Input
Output
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 }