您的位置:首页 > 理论基础 > 计算机网络

[POJ1637]混合图的欧拉回路判定|网络流

2015-04-14 20:46 253 查看
  混合图的欧拉回路判定

  上一篇正好分别讲了有向图和无向图的欧拉回路判定方法

  如果遇上了混合图要怎么做呢?

  首先我们思考有向图的判定方法:所有点的出度=入度

  我们可以先为无向边任意定一个向,算出此时所有顶点的入度和出度

  对于一个入度<>出度的点,我们修改与它相连的一条无向边的方向,一种可能是入度-1出度+1,一种可能是入度+1出度-1

  无论如何不会改变的是其入度与出度的差一直是偶数

  所以首先我们对任意定向后的整张图根据其入度与出度之差进行初步判定

  有顶点入度与出度之差为奇数的图一定无法构成欧拉回路

  接下来继续看,对于每一条任意定向的无向边:



  我们改变了方向之后可以将a[u]-b[u]的差增加2,将a[v]-b[v]的差减小2

  我们可以根据a[i]与b[i]的差计算出要使a[i]=b[i]时需要几条原来从a[i]出发的边反向

  同时要考虑到a[i]也可能作为原来作为终点

  我们可以据此建立起网络流的模型

  建立一个源点s和一个汇点t

  对于所有a[i]>b[i]的点,从s到i建立一条容量为c=(a[i]-b[i]) >> 1的边(如果这些流量都流完了,点i的出入度就相同了

  我们期望流过c流量的边,我们希望通过c条原本起点为i的边反转从而达到这样的目的

  同样的,对于所有a[i]<b[i]的点,从i到t建立一条容量为(b[i]-a[i]) >> 1的边(如果这些流量流完了,点i的出入度就相同了

  我们期望流过c流量的边,通过c条原本终点为i的边反转

  当然不排除尽管位于左侧但仍然要作为终点的情况,这个时候增加的a[i]-b[i]的差我们要通过更多原本以i为起点的边反转

  网络流正好满足这个性质,从其他点流过来的流量我们需要推出去更多的流量

  所以对于原本定向为(x,y)的边,我们从x到y连一条流量为1的边

  为了优化这个操作,使边数更小,我们可以累计x到y的边,最后加边

  这里思考一下为什么不能将每条边当做的流量乘二,与源点汇点的流量不用除以2

  这就防止了一条边被拆做两个半条用的情况

  至于怎样才算成功,即所有从源点发出去的流量=留回汇点的流量


附上原题描述以及代码



  Sightseeing tour

Description

  The city executive board in Lund wants to construct a sightseeing tour by bus in Lund, so that tourists can see every corner of the beautiful city. They want to construct the tour so that every street in the city is visited exactly once. The bus should also start and end at the same junction. As in any city, the streets are either one-way or two-way, traffic rules that must be obeyed by the tour bus. Help the executive board and determine if it's possible to construct a sightseeing tour under these constraints.

program poj1637;
const maxn=210;maxm=80010;
var fa,next,w,rec:array[-1..maxm]of longint;
opt,link,dis,a,b:array[-1..maxn]of longint;
t,test,n,m,ans,j,s,tt,i:longint;
e:array[-1..maxm]of record x,y,z:longint;end;
c:array[-1..maxn,-1..maxn]of longint;

function min(a,b:longint):longint;
begin
if a<b then exit(a) else exit(b);
end;

procedure add(x,y,z:longint);
begin
inc(j);fa[j]:=y;next[j]:=link[x];link[x]:=j;w[j]:=z;rec[j]:=j+1;
inc(j);fa[j]:=x;next[j]:=link[y];link[y]:=j;w[j]:=0;rec[j]:=j-1;
end;

function spfa:boolean;
var head,tail,x,j:longint;
begin
fillchar(dis,sizeof(dis),63);
head:=0;tail:=1;opt[1]:=s;dis[s]:=0;
while head<>tail do
begin
head:=(head+1)mod maxn;
x:=opt[head];j:=link[x];
while j<>0 do
begin
if (dis[x]+1<dis[fa[j]])and(w[j]>0) then
begin
dis[fa[j]]:=dis[x]+1;
tail:=(tail+1) mod maxn;opt[tail]:=fa[j];
end;
j:=next[j];
end;
end;
if dis[t]<>dis[-1] then exit(true) else exit(false);
end;

function dfs(p,sum:longint):longint;
var j,tem,x:longint;
begin
tem:=0;
if p=t then exit(sum);
j:=link[p];
while j<>0 do
begin
if (dis[fa[j]]=dis[p]+1)and(w[j]>0) then
begin
x:=dfs(fa[j],min(sum-tem,w[j]));
inc(tem,x);dec(w[j],x);inc(w[rec[j]],x);
if tem=sum then exit(sum);
end;
j:=next[j];
end;
exit(tem);
end;

function check:boolean;
var i,k:longint;
begin
j:=0;s:=0;t:=n+1;ans:=0;
fillchar(c,sizeof(c),0);
for i:=1 to n do if odd(abs(a[i]-b[i])) then exit(false);
for i:=1 to m do if e[i].z=0 then inc(c[e[i].x,e[i].y]);
for i:=1 to n do if a[i]-b[i]>0 then
begin
add(s,i,(a[i]-b[i]) >> 1);
inc(ans,(a[i]-b[i]) >> 1);
end
else
if b[i]-a[i]>0 then add(i,t,(b[i]-a[i]) >> 1);
for i:=1 to n do
for k:=1 to n do if c[i,k]>0 then add(i,k,c[i,k]);
while (spfa)and(ans>0) do
dec(ans,dfs(s,ans));
if ans=0 then exit(true) else exit(false);
end;

begin
readln(test);
for tt:=1 to test do
begin
readln(n,m);
fillchar(link,sizeof(link),0);
fillchar(next,sizeof(next),0);
for i:=1 to n do
begin
a[i]:=0;b[i]:=0;
end;
for i:=1 to m do
begin
readln(e[i].x,e[i].y,e[i].z);
inc(a[e[i].x]);inc(b[e[i].y]);
end;
if check then writeln('possible') else writeln('impossible');
end;
end.


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