前面讲过了无向图,有向图求欧拉回路,欧拉通路的做法。可以直接根据度数来判断,当然前提是这是一个连通图。
这道题既有无向边,又有有向边,然后求欧拉回路。
采用的方法是最大流。
具体处理方法。
首先,我们对无向边,进行随意定边。定完边之后,求出每个点的出度入度。如果某个点的出度入度之差为奇数,那么就无法形成欧拉回路。
接下来所有的点的度数之差都是偶数了,对于有向边,我们不需要处理。
对于无向边,我们给初始随意定的边的方向,流量+1,即如果一条无向边,a - b,我们初始给他定边是a -> b,那么我们将a -> b的流量+1。
然后对于每个入度出度之差为偶数的点,如果出度大于入度。那么我们连一条S到该点的边,流量为 (出度 - 入度)/ 2 。
同理,对于入度大于出度的边,我们连一条该点到T的边,流量为(入度- 出度)/ 2 。
接下来我们跑一遍最大流即可以了。
如果该图是满流的话,那么证明存在欧拉回路。否则不存在。
具体证明请看这里。http://zhyu.me/acm/zoj-1992-and-poj-1637.html
CODE:
#include <iostream> #include <cstdio> #include <algorithm> #include <string> #include <cmath> #include <cstring> #include <queue> #include <set> #include <vector> #include <stack> #include <map> #include <iomanip> #define PI acos(-1.0) #define Max 2505 #define inf 1<<28 #define LL(x) ( x << 1 ) #define RR(x) ( x << 1 | 1 ) #define REP(i,s,t) for( int i = ( s ) ; i <= ( t ) ; ++ i ) #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) #define mp(a,b) make_pair(a,b) #define PII pair<int,int> using namespace std; inline void RD(int &ret) { char c; do { c = getchar(); } while(c < '0' || c > '9') ; ret = c - '0'; while((c=getchar()) >= '0' && c <= '9') ret = ret * 10 + ( c - '0' ); } inline void OT(int a){ if(a >= 10)OT(a / 10) ; putchar(a % 10 + '0') ; } #define N 1005 #define M 100005 struct ed{ int s , e , flag ; }road[M] ; int in[N] ,out[N] ; struct kdq{ int e , next ,c ; }ed[M] ; int head[N] ,num ; void add(int s ,int e ,int c){ ed[num].e = e ; ed[num].c = c ; ed[num].next = head[s] ; head[s] = num ++ ; ed[num].e = s ; ed[num].c = 0 ; ed[num].next = head[e] ; head[e] = num ++ ; } void init(){ mem(head , -1) ; mem(in , 0) ; mem(out , 0) ; } int S , T ; int dis[N] ,qe[M] ,deep[N] ; int n , m ; /***dinic模版***/ int dinic_bfs(){ mem(deep, -1) ; deep[S] = 0 ; int h = 0 , t = 0 ; qe[h ++ ] = S ; while(h > t){ int tt = qe[t ++ ] ; for (int i = head[tt] ; ~i ; i = ed[i].next ){ int e = ed[i].e ; int c = ed[i].c ; if(c > 0 && deep[e] == -1){ deep[e] = deep[tt] + 1 ; qe[h ++ ] = e ; } } } return deep[T] != -1 ; } int dinic_dfs(int now ,int f){ if(now == T)return f ; int flow = 0 ; for (int i = head[now] ; ~i ; i = ed[i].next ){ int e = ed[i].e ; int c = ed[i].c ; if((f - flow) > 0 && c > 0 && deep[e] == deep[now] + 1 ){ int mm = min(f - flow ,c) ; int nn = dinic_dfs(e , mm) ; flow += nn ; ed[i].c -= nn ; ed[i ^ 1].c += nn ; } } if(flow == 0)deep[now] = -2 ; return flow ; } int dinic(){ int MaxFlow = 0 ; while(dinic_bfs()){ MaxFlow += dinic_dfs(S ,inf) ; } return MaxFlow ; } /******/ int main() { int t ; cin >> t ; while(t -- ){ cin >> n >> m ; init() ; S = 0 , T = n + 1 ; for (int i = 1 ; i <= m ; i ++){ RD(road[i].s) ;RD(road[i].e) ;RD(road[i].flag) ; out[road[i].s] ++ ; in[road[i].e] ++ ; } bool flag = 0 ; for (int i = 1 ; i <= n ; i ++ ){ if(abs(in[i] - out[i]) & 1){//存在度数之差为奇数的点 puts("impossible") ; flag = 1 ; break ; } } if(flag)continue ; for (int i = 1 ; i <= m ;i ++ ){ if(road[i].flag)continue ; add(road[i].s ,road[i].e , 1) ;//初始定边我都是按a -> b的方向 } int MF = 0 ; for (int i = 1 ; i <= n ; i ++ ){ if(out[i] > in[i]){ add(S , i , (out[i] - in[i]) / 2 ) ; MF += (out[i] - in[i]) / 2 ; } else if(in[i] > out[i]){ add(i , T , (in[i] - out[i]) / 2) ; } } int MaxFlow = dinic() ; if(MaxFlow == MF){ puts("possible") ; } else puts("impossible") ; } return 0 ; }