POJ 1637 混合图的欧拉回路 网络流

来源:互联网 发布:中兴软创 知乎 编辑:程序博客网 时间:2024/05/16 01:52

题目链接:http://poj.org/problem?id=1637

题意:就是判断一个混合图是否有欧拉回路

解法:

其实,难点在于图中的无向边,需要对所有的无向边定向(指定一个方向,使之变为有向边),使整个图变成

一个有向欧拉图(或有向半欧拉图)。若存在一个定向满足此条件,则原图是欧拉图(或半欧拉图)否则不

是。关键就是如何定向?

首先给原图中的每条无向边随便指定一个方向(称为初始定向),将原图改为有向图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引出的边中有的没有满流,则原混合图不是欧拉图。

证明的话见邝斌巨苣的博客:

http://www.cnblogs.com/kuangbin/p/3537525.html orz

就这个题本身而言,知道如何建图判定就可以了,证明感觉不是太重要,这是对我这种一向不会证明的我人来

说QAQ

#include <stdio.h>#include <string.h>#include <iostream>#include <algorithm>using namespace std;const int maxn = 1010;const int maxm = 510010;const int inf = 0x3f3f3f3f;struct G{    int v, cap, next;    G() {}    G(int v, int cap, int next) : v(v), cap(cap), next(next) {}} E[maxm];int p[maxn], T;int d[maxn], temp_p[maxn], qw[maxn]; //d顶点到源点的距离标号,temp_p当前狐优化,qw队列void init(){    memset(p, -1, sizeof(p));    T = 0;}void add(int u, int v, int cap){    E[T] = G(v, cap, p[u]);    p[u] = T++;    E[T] = G(u, 0, p[v]);    p[v] = T++;}bool bfs(int st, int en, int n){    int i, u, v, head, tail;    for(i = 0; i <= n; i++) d[i] = -1;    head = tail = 0;    d[st] = 0;    qw[tail] = st;    while(head <= tail)    {        u = qw[head++];        for(i = p[u]; i + 1; i = E[i].next)        {            v = E[i].v;            if(d[v] == -1 && E[i].cap > 0)            {                d[v] = d[u] + 1;                qw[++tail] = v;            }        }    }    return (d[en] != -1);}int dfs(int u, int en, int f){    if(u == en || f == 0) return f;    int flow = 0, temp;    for(; temp_p[u] + 1; temp_p[u] = E[temp_p[u]].next)    {        G& e = E[temp_p[u]];        if(d[u] + 1 == d[e.v])        {            temp = dfs(e.v, en, min(f, e.cap));            if(temp > 0)            {                e.cap -= temp;                E[temp_p[u] ^ 1].cap += temp;                flow += temp;                f -= temp;                if(f == 0)  break;            }        }    }    return flow;}int dinic(int st, int en, int n){    int i, ans = 0;    while(bfs(st, en, n))    {        for(i = 0; i <= n; i++) temp_p[i] = p[i];        ans += dfs(st, en, inf);    }    return ans;}int in[maxn], out[maxn];int main(){    int T, n, m;    scanf("%d", &T);    while(T--){        scanf("%d%d", &n,&m);        init();        memset(in, 0, sizeof(in));        memset(out, 0, sizeof(out));        while(m--){            int u, v, w;            scanf("%d%d%d", &u,&v,&w);            in[v]++, out[u]++;            if(w == 0) add(u, v, 1);        }        bool flag = 1;        for(int i = 1; i<= n; i++){            int D = in[i]-out[i];            if(D%2){                flag = 0;                break;            }            if(D<0){                D = -D;                add(0, i, D/2);            }            else{                add(i, n+1, D/2);            }        }        if(flag==0){            printf("impossible\n");            continue;        }        dinic(0, n+1, n+2);        for(int i = p[0]; ~i; i = E[i].next){            if(E[i].cap){                flag = 0;                break;            }        }        if(flag) printf("possible\n");        else printf("impossible\n");    }    return 0;}
0 0
原创粉丝点击