zoukankan      html  css  js  c++  java
  • [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.
  • 相关阅读:
    Advanced-REST-client安装
    啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊
    mysql5.6 的st_distance 实现按照距离远近排序。
    Springboot读取配置文件及自定义配置文件
    mysql distinct
    SOAP XML报文解析
    提交post请求,参数为xml格式
    docker中tomcat日志输出自定义
    Vmware centos 虚拟机 磁盘扩容
    vim开发配置
  • 原文地址:https://www.cnblogs.com/mjy0724/p/4426010.html
Copyright © 2011-2022 走看看