您的位置:首页 > 其它

混合图的欧拉回路POJ1637

2010-11-15 08:57 281 查看
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;
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: