http://poj.org/problem?id=1637
/* 题意就是给你一个地图:有无向图,也有有向图,然后叫你能不能找出一条路径,看是否全部走完,其实就是求 混合图的欧拉回路 解题思路: 求混合图的欧拉回路就是用网络流来解决 1. 把该图的无向边随便定向,计算每个点的入度和出度。如果有某个点出入度之差为奇数,那么肯定不存在欧拉回路。因为欧拉回路要求每点入度 = 出度, 也就是总度数为偶数,存在奇数度点必不能有欧拉回路。 2. 现在每个点入度和出度之差均为偶数。那么将这个偶数除以2,得x。也就是说,对于每一个点, 只要将x条边改变方向(入>出就是变入,出>入就是变出),就能保证出 = 入。如果每个点都是出 = 入, 那么很明显,该图就存在欧拉回路。 3. 我该改变哪些边,可以让每个点出 = 入?构造网络流模型。有向边是不能改变方向的 4. 无向边的流量限制为1 5. 另新建s和t。对于入 > 出的点u,连接边(u, t)、容量为x 6. 对于出 > 入的点v,连接边(s, v),容量为x(注意对不同的点x不同)。 */ #include<iostream> using namespace std; #define MAXN 205 #define inf 0x7fffffff int cap[MAXN][MAXN], flow[MAXN][MAXN]; int s, t, n; int queue[MAXN], head, tail, maxflow, pre[MAXN]; bool findload()//bfs找增广路 { int i, tmp; memset(pre, -1, sizeof(pre)); head = tail = 0; queue[tail++] = s; pre[s] = s; while(head < tail) { tmp = queue[head++]; for(i=1; i<=n; i++) { if(pre[i] == -1 && cap[tmp][i] - flow[tmp][i] > 0) { pre[i] = tmp; if(i == t)//找到一条增广路 return true; queue[tail++] = i; } } } return false; } int ek() { int i; maxflow = 0; memset(flow, 0, sizeof(flow)); while(findload()) { int min = inf; for(i=t; i!=s; i = pre[i])//增广路径中的最小可行流 { if(min > cap[pre[i]][i] - flow[pre[i]][i]) min = cap[pre[i]][i] - flow[pre[i]][i]; } for(i=t; i!=s; i = pre[i])//调整路径上的流 { flow[pre[i]][i] += min; flow[i][pre[i]] -= min; } maxflow += min;//最大流累加 } return maxflow; } int tt, m, ss, indeg[MAXN], outdeg[MAXN], map[1010][2], cnt, from, to, di; int main() { freopen("in.txt", "r", stdin); int i; scanf("%d", &tt); while(tt--) { scanf("%d %d", &m, &ss); memset(indeg, 0, sizeof(indeg)); memset(outdeg, 0, sizeof(outdeg)); cnt = 0; for(i=0; i<ss; i++) { scanf("%d %d %d", &from, &to, &di); indeg[to]++; outdeg[from]++; map[cnt][0] = from;//记录无向边 map[cnt][1] = to; if(!di)//无向边 cnt++; } /* for(i=1; i<=m; i++) printf("%d %d/n", indeg[i], outdeg[i]); printf("%d/n", cnt);*/ bool flag = true; for(i=1; i<=m; i++) if((indeg[i] - outdeg[i])%2 != 0) { flag = false; break; } else indeg[i] = (indeg[i] - outdeg[i])/2; s = 1;//源点 t = 1 + m + 1;//汇点 n = m + 2;//总的边数 if(flag) { memset(cap, 0, sizeof(cap)); for(i=0; i<cnt; i++)//无向边的边数 cap[map[i][0]+1][map[i][1]+1]++; int sum = 0; for(i=1; i<=m; i++) { if(indeg[i] > 0)//如果入度大于出度 { cap[i+1][t] = indeg[i]; sum += indeg[i]; } else if(indeg[i] < 0)//入度小于出度 cap[s][i+1] = -indeg[i]; } if(sum != ek())//如果不相等 flag = false; } if(flag) printf("possible/n"); else printf("impossible/n"); } return 0; }