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

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

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

采用的方法是最大流。

具体处理方法。

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

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

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

}


 

 

你可能感兴趣的:(poj)