POJ 1637 混合图求欧拉回路 最大流实现

来源:互联网 发布:遗传算法c 实现 编辑:程序博客网 时间:2024/06/05 15:02

前面讲过了无向图,有向图求欧拉回路,欧拉通路的做法。可以直接根据度数来判断,当然前提是这是一个连通图。

这道题既有无向边,又有有向边,然后求欧拉回路。

采用的方法是最大流。

具体处理方法。

首先,我们对无向边,进行随意定边。定完边之后,求出每个点的出度入度。如果某个点的出度入度之差为奇数,那么就无法形成欧拉回路。

接下来所有的点的度数之差都是偶数了,对于有向边,我们不需要处理。

对于无向边,我们给初始随意定的边的方向,流量+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 100005struct 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 ;}