2011.08.03

前几天由于断网一直把写博的事情耽误了,现在可以继续了~


POJ 1637 Sightseeing Tour

        题意:求混合图的欧拉回路。

        方法:用最大流解决,见下文。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<fstream>
#include<memory>
#define MAXV 1005
#define MAXE 100005
using namespace std;
const int inf=1<<30-1;
int du[MAXV];
int sum,ans,pos,s,t;
int dist[MAXV]= {0}, numbs[MAXV] = {0}, src, des, n;
const int infinity = inf;
struct edge{
    int ver;    // vertex
    int cap;    // capacity
    int flow;   // current flow in this arc
    edge *next; // next arc
    edge *rev;  // reverse arc
    edge(){}
    edge(int Vertex, int Capacity, edge *Next)
        :ver(Vertex), cap(Capacity), flow(0), next(Next), rev((edge*)NULL){}
    void* operator new(size_t, void *p){
        return p;
    }
}*Net[MAXV];
void rev_BFS(){
    int Q[MAXV], head = 0, tail = 0;
    for(int i=1; i<=n; ++i){
        dist[i] = MAXV;
        numbs[i] = 0;
    }
    Q[tail++] = des;
    dist[des] = 0;
    numbs[0] = 1;
    while(head != tail){
        int v = Q[head++];
        for(edge *e = Net[v]; e; e = e->next){
            if(e->rev->cap == 0 || dist[e->ver] < MAXV)continue;
            dist[e->ver] = dist[v] + 1;
            ++numbs[dist[e->ver]];
            Q[tail++] = e->ver;
        }
    }
}
int maxflow(){
    int u, totalflow = 0;
    edge *CurEdge[MAXV], *revpath[MAXV];
    for(int i=1; i<=n; ++i)CurEdge[i] = Net[i];
    u = src;
    while(dist[src] < n){
        if(u == des){    // find an augmenting path
            int augflow = infinity;
            for(int i = src; i != des; i = CurEdge[i]->ver)
                augflow = min(augflow, CurEdge[i]->cap);
            for(int i = src; i != des; i = CurEdge[i]->ver){
                CurEdge[i]->cap -= augflow;
                CurEdge[i]->rev->cap += augflow;
                CurEdge[i]->flow += augflow;
                CurEdge[i]->rev->flow -= augflow;
            }
            totalflow += augflow;
            u = src;
        }
        edge *e;
        for(e = CurEdge[u]; e; e = e->next)
            if(e->cap > 0 && dist[u] == dist[e->ver] + 1)break;
        if(e){    // find an admissible arc, then Advance
            CurEdge[u] = e;
            revpath[e->ver] = e->rev;
            u = e->ver;
        } else {    // no admissible arc, then relabel this vertex
            if(0 == (--numbs[dist[u]]))break;    // GAP cut, Important!
            CurEdge[u] = Net[u];
            int mindist = n;
            for(edge *te = Net[u]; te; te = te->next)
                if(te->cap > 0)mindist = min(mindist, dist[te->ver]);
            dist[u] = mindist + 1;
            ++numbs[dist[u]];
            if(u != src)
                u = revpath[u]->ver;    // Backtrack
        }
    }
    return totalflow;
}
int main()
{
 	freopen("in.txt","r",stdin);
 	freopen("out.txt","w",stdout);
    int Case,m,u,v,x,i,j,ok;
    scanf("%d",&Case);
    while(Case--){
        memset(du,0,sizeof(du));
        memset(Net,0,sizeof(Net));
        memset(numbs,0,sizeof(numbs));
        memset(dist,0,sizeof(dist));
        scanf("%d%d",&n,&m);
        ok=1;
        s=n+1;t=n+2;
        src = s; des =t;
        edge *buffer = new edge[MAXE];
        edge *data = buffer;
        while(m--){
            scanf("%d%d%d",&u,&v,&x);
            if(u==v)continue;
            du[u]++;du[v]--;
            if(!x) {
                Net[u] = new((void*) data++) edge(v, inf, Net[u]);
                Net[v] = new((void*) data++) edge(u, 0, Net[v]);
                Net[u]->rev = Net[v];
                Net[v]->rev = Net[u];
            }
        }
        for(i=1;i<=n;i++){
            if((du[i]+1000)%2)
                break;
            du[i]/=2;
            if(du[i]>0){
                Net[s] = new((void*) data++) edge(i,du[i], Net[s]);
                Net[i] = new((void*) data++) edge(s, 0, Net[i]);
                Net[s]->rev = Net[i];
                Net[i]->rev = Net[s];
                sum+=du[i];
            }
            else{
                Net[i] = new((void*) data++) edge(t,-du[i], Net[i]);
                Net[t] = new((void*) data++) edge(i, 0, Net[t]);
                Net[i]->rev = Net[t];
                Net[t]->rev = Net[i];
            }
        }
        if(i<=n)
            printf("impossible\n");
        else {
			 n+=2;
        	 rev_BFS();
        	 int ans=maxflow();
        	 if(ans==sum) printf("possible\n");
        	 else printf("impossible\n");
	    }
        sum=0;
        delete [] buffer;
    }
    return 0;
}

欧拉路:

欧拉通路 (Euler tour)——通过图中每条边一次且仅一次,并且过每一顶点的通路。

欧拉回路 (Euler circuit)——通过图中每条边一次且仅一次,并且过每一顶点的回路。

欧拉图——存在欧拉回路的图。

欧拉回路的判断:

        此图的基图连通的条件下:

        无向图存在欧拉回路条件

          一个无向图存在欧拉回路,当且仅当该图所有顶点度数都是偶数。

        有向图存在欧拉回路条件

          一个有向图存在欧拉回路,且所有顶点的入度等于出度

        混合图存在欧拉回路条件

         假设有一张图有向图G',在不论方向的情况下它与G同构。并且G'包含了G的所有有向边。那么如果存在一个图G'使得G'存在欧拉回路,那么G就存在欧拉回路。

 具体思路

   把该图的无向边随便定向,计算每个点的入度和出度。如果有某个点出入度之差为奇数, 那么肯定不存在欧拉回路。因为欧拉回路要求每点入度 = 出度,也就是总度数为偶数,存在奇数度点必不能有欧拉回路。 好了,现在每个点入度和出度之差均为偶数。那么将这个偶数除以2,得x。 也就是说,对于每一个点,只要将x条边改变方向(入>出就是变入,出>入就是变出), 就能保证出 = 入。如果每个点都是出 = 入,那么很明显,该图就存在欧拉回路。 现在的问题就变成了:我该改变哪些边,可以让每个点出 = 入?构造网络流模型。首先,有向边是不能改变方向的,要之无用,删。 一开始不是把无向边定向了吗?定的是什么向,就把网络构建成什么样,边长容量上限1(说inf的果然不对嘛…)。另新建s和t。对于入 > 出的点u,连接边(u, t)、容量为x, 对于出 > 入的点v,连接边(s, v),容量为x(注意对不同的点x不同)。之后,察看是否有满流的分配。有就是能有欧拉回路,没有就是没有。欧拉回路是哪个? 察看流值分配,将所有流量非0(上限是1,流值不是0就是1)的边反向,就能得到每点入度 = 出度的欧拉图。 由于是满流,所以每个入 > 出的点,都有x条边进来,将这些进来的边反向,OK,入 = 出了。对于出 > 入的点亦然。 那么,没和s、t连接的点怎么办?和s连接的条件是出 > 入,和t连接的条件是入 > 出,那么这个既没和s也没和t连接的点,自然早在开始就已经满足入 = 出了。 那么在网络流过程中,这些点属于“中间点”。我们知道中间点流量不允许有累积的,这样,进去多少就出来多少,反向之后,自然仍保持平衡。 所以,就这样,混合图欧拉回路问题,解了。

        混合图的欧拉回路, 既然是欧拉回路首先图必须是连通的:将所有边看成无向边做一遍dfs判断连通性。要构成欧拉图最后所以得点入度都等于出度,即需要每个点入度和出度之差为偶数,若有两个点为奇数可能有欧拉路,这时只需要在这两个点之间加一条边,即可转化为欧拉回路问题。判断完毕后,如果所有点入度和出度差为偶数,构建网络流图,原来图中的有向边,可以删去。

        转自:http://www.cppblog.com/yuan1028/archive/2010/07/31/121748.html


        杯了个具,codeforce又要掉rating了ORZ…

        晚安世界,以后比赛还是不只切图论了吧,笨蛋……

把该图的无向边随便定向,计算每个点的入度和出度。如果有某个点出入度之差为奇数,
那么肯定不存在欧拉回路。因为欧拉回路要求每点入度 = 出度,也就是总度数为偶数,存在奇数度点必不能有欧拉回路。
好了,现在每个点入度和出度之差均为偶数。那么将这个偶数除以2,得x。
也就是说,对于每一个点,只要将x条边改变方向(入>出就是变入,出>入就是变出),
就能保证出 = 入。如果每个点都是出 = 入,那么很明显,该图就存在欧拉回路。
现在的问题就变成了:我该改变哪些边,可以让每个点出 = 入?构造网络流模型。首先,有向边是不能改变方向的,要之无用,删。
一开始不是把无向边定向了吗?定的是什么向,就把网络构建成什么样,边长容量上限1。另新建s和t。对于入 > 出的点u,连接边(u, t)、容量为x,
对于出 > 入的点v,连接边(s, v),容量为x(注意对不同的点x不同)。之后,察看是否有满流的分配。有就是能有欧拉回路,没有就是没有。欧拉回路是哪个?
察看流值分配,将所有流量非0(上限是1,流值不是0就是1)的边反向,就能得到每点入度 = 出度的欧拉图。
由于是满流,所以每个入 > 出的点,都有x条边进来,将这些进来的边反向,OK,入 = 出了。对于出 > 入的点亦然。
那么,没和s、t连接的点怎么办?和s连接的条件是出 > 入,和t连接的条件是入 > 出,那么这个既没和s也没和t连接的点,自然早在开始就已经满足入 = 出了。
那么在网络流过程中,这些点属于“中间点”。我们知道中间点流量不允许有累积的,这样,进去多少就出来多少,反向之后,自然仍保持平衡。
所以,就这样,混合图欧拉回路问题,解了.

上文是pku的discuss中的,下面自己总结一下。 
混合图的欧拉回路, 既然是欧拉回路首先图必须是连通的:将所有边看成无向边做一遍dfs判断连通性。
要构成欧拉图最后所以得点入度都等于出度,即需要每个点入度和出度之差为偶数,若有两个点为奇数可能有欧拉路,
这时只需要在这两个点之间加一条边,即可转化为欧拉回路问题。

判断完毕后,如果所有点入度和出度差为偶数,构建网络流图,原来图中的有向边,可以删去。
原来的无向边可以任意指定一个方向,之后对所有入度大于出度的点引一条边到汇点,边权为入度与出度差的一半。
对于出度大于入度的点从源点引一条边过来,边权为出度和入度差的一半,最后求最大流,若是漫流,则证明有欧拉回路。

把该图的无向边随便定向,计算每个点的入度和出度。如果有某个点出入度之差为奇数,
那么肯定不存在欧拉回路。因为欧拉回路要求每点入度 = 出度,也就是总度数为偶数,存在奇数度点必不能有欧拉回路。
好了,现在每个点入度和出度之差均为偶数。那么将这个偶数除以2,得x。
也就是说,对于每一个点,只要将x条边改变方向(入>出就是变入,出>入就是变出),
就能保证出 = 入。如果每个点都是出 = 入,那么很明显,该图就存在欧拉回路。
现在的问题就变成了:我该改变哪些边,可以让每个点出 = 入?构造网络流模型。首先,有向边是不能改变方向的,要之无用,删。
一开始不是把无向边定向了吗?定的是什么向,就把网络构建成什么样,边长容量上限1。另新建s和t。对于入 > 出的点u,连接边(u, t)、容量为x,
对于出 > 入的点v,连接边(s, v),容量为x(注意对不同的点x不同)。之后,察看是否有满流的分配。有就是能有欧拉回路,没有就是没有。欧拉回路是哪个?
察看流值分配,将所有流量非0(上限是1,流值不是0就是1)的边反向,就能得到每点入度 = 出度的欧拉图。
由于是满流,所以每个入 > 出的点,都有x条边进来,将这些进来的边反向,OK,入 = 出了。对于出 > 入的点亦然。
那么,没和s、t连接的点怎么办?和s连接的条件是出 > 入,和t连接的条件是入 > 出,那么这个既没和s也没和t连接的点,自然早在开始就已经满足入 = 出了。
那么在网络流过程中,这些点属于“中间点”。我们知道中间点流量不允许有累积的,这样,进去多少就出来多少,反向之后,自然仍保持平衡。
所以,就这样,混合图欧拉回路问题,解了.

上文是pku的discuss中的,下面自己总结一下。 
混合图的欧拉回路, 既然是欧拉回路首先图必须是连通的:将所有边看成无向边做一遍dfs判断连通性。
要构成欧拉图最后所以得点入度都等于出度,即需要每个点入度和出度之差为偶数,若有两个点为奇数可能有欧拉路,
这时只需要在这两个点之间加一条边,即可转化为欧拉回路问题。

判断完毕后,如果所有点入度和出度差为偶数,构建网络流图,原来图中的有向边,可以删去。
原来的无向边可以任意指定一个方向,之后对所有入度大于出度的点引一条边到汇点,边权为入度与出度差的一半。
对于出度大于入度的点从源点引一条边过来,边权为出度和入度差的一半,最后求最大流,若是漫流,则证明有欧拉回路。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值