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

  混合图的欧拉回路判定

 

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

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

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

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

  对于一个入度<>出度的点,我们修改与它相连的一条无向边的方向,一种可能是入度-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.

 

 

 

 

 

 

 

 

 

 

posted @ 2015-04-14 20:46  mjy0724  阅读(211)  评论(0编辑  收藏  举报