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