题目链接: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;
}