您的位置:首页 > 其它

poj1637(混合图判欧拉回路)

2017-09-11 20:46 337 查看
把该图的无向边随便定向,计算每个点的入度和出度。如果有某个点出入度

之差为奇数,那么肯定不存在欧拉回路。因为欧拉回路要求每点入度 = 出度,

也就是总度数为偶数,存在奇数度点必不能有欧拉回路。

 好了,现在每个点入度和出度之差均为偶数。那么将这个偶数除以 2,得 x。

也就是说,对于每一个点,只要将 x 条边改变方向(入>出就是变入,出>入就是

9

变出),就能保证出=入。如果每个点都是出=入,那么很明显,该图就存在欧拉

回路。

 现在的问题就变成了:我该改变哪些边,可以让每个点出=入?构造网络流

模型。首先,有向边是不能改变方向的,要之无用,删。一开始不是把无向边定

向了吗?定的是什么向,就把网络构建成什么样,边长容量上限 1。另新建 s 和

t。对于入>出的点 u,连接边(u, t)、容量为 x,对于出>入的点 v,连接边(s, v),

容量为 x(注意对不同的点 x 不同)。之后,察看是否有满流的分配。有就是能

有欧拉回路,没有就是没有。欧拉回路是哪个?察看流值分配,将所有流量非 0

(上限是 1,流值不是 0 就是 1)的边反向,就能得到每点入度=出度的欧拉图。

 由于是满流,所以每个入>出的点,都有 x 条边进来,将这些进来的边反向,

OK,入=出了。对于出>入的点亦然。那么,没和 s、t 连接的点怎么办?和 s 连

接的条件是出>入,和 t 连接的条件是入>出,那么这个既没和 s 也没和 t 连接的

点,自然早在开始就已经满足入=出了。那么在网络流过程中,这些点属于“中

间点”。我们知道中间点流量不允许有累积的,这样,进去多少就出来多少,反

向之后,自然仍保持平衡。
所以,就这样,混合图欧拉回路问题,解了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
////////////////////////最大流开始//////////////////////////////////////
typedef int cap_type;
#define MAX_V 500 + 30 + 16

// 用于表示边的结构体(终点、容量、反向边)
struct edge
{
int to, rev;
cap_type cap;

edge(int to, cap_type cap, int rev) : to(to), cap(cap), rev(rev)
{}
};

vector <edge> G[MAX_V]; // 图的邻接表表示
int level[MAX_V]; // 顶点到源点的距离标号
int iter[MAX_V]; // 当前弧,在其之前的边已经没有用了

// 向图中加入一条从from到to的容量为cap的边
void add_edge(int from, int to, int cap)
{
G[from].push_back(edge(to, cap, G[to].size()));
G[to].push_back(edge(from, 0, G[from].size() - 1));
}

// 通过BFS计算从源点出发的距离标号
void bfs(int s)
{
memset(level, -1, sizeof(level));
queue<int> que;
level[s] = 0;
que.push(s);
while (!que.empty())
{
int v = que.front();
que.pop();
for (int i = 0; i < G[v].size(); ++i)
{
edge &e = G[v][i];
if (e.cap > 0 && leve
4000
l[e.to] < 0)
{
level[e.to] = level[v] + 1;
que.push(e.to);
}
}
}
}

// 通过DFS寻找增广路
cap_type dfs(int v, int t, cap_type f)
{
if (v == t)
{
return f;
}
for (int &i = iter[v]; i < G[v].size(); ++i)
{
edge &e = G[v][i];
if (e.cap > 0 && level[v] < level[e.to])
{
cap_type d = dfs(e.to, t, min(f, e.cap));
if (d > 0)
{
e.cap -= d;
G[e.to][e.rev].cap += d;
return d;
}
}
}

return 0;
}

// 求解从s到t的最大流
cap_type max_flow(int s, int t)
{
cap_type flow = 0;
for (;;)
{
bfs(s);
if (level[t] < 0)
{
return flow;
}
memset(iter, 0, sizeof(iter));
cap_type f;
while ((f = dfs(s, t, 0x3f3f3f3f3f3f3f3f)) > 0)
{
flow += f;
}
}
}
///////////////////////////////最大流结束/////////////////////////////////////
vector<int>g[205];
int in[205],out[205];
int main()
{
int cases,n,m,u,v,w,s,t;
scanf("%d",&cases);
while(cases--)
{
scanf("%d%d",&n,&m);
for(int i=0;i<=n;i++) g[i].clear();
for(int i=0;i<=300;i++) G[i].clear();
memset(in,0,sizeof(in)); memset(out,0,sizeof(out));
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&u,&v,&w);
in[v]++; out[u] ++;
if(!w)
g[u].push_back(v);
}
int f = 1;
for(int i=1;i<=n;i++)
if(abs(in[i]-out[i])%2!=0)
{ f = 0; break; }
if(!f) { printf("impossible\n"); continue;}
s = n+1; t = s+1; int tot = 0;
for(int i=1;i<=n;i++)
if(in[i]<out[i]){ add_edge(s,i,(out[i]-in[i])/2); tot += (out[i]-in[i])/2; }
else if(in[i]>out[i]){add_edge(i,t,(in[i]-out[i])/2);}
for(int i=1;i<=n;i++)
{
int len = g[i].size();
for(int k=0;k<len;k++)
{
int j = g[i][k];
add_edge(i,j,1);
}
}
//printf("%d %d\n",max_flow(s,t),tot);
if(max_flow(s,t)==tot) printf("possible\n");
else printf("impossible\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: