现在的位置: 首页 > 综合 > 正文

poj 1637(求混合图的欧拉回路是否存在:构造网络流求解)

2018年05月01日 ⁄ 综合 ⁄ 共 3530字 ⁄ 字号 评论关闭

思路是别人的,代码是自己的,自己的模版题。

1 定义

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


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

2 无向图是否具有欧拉通路或回路的判定

G有欧拉通路的充分必要条件为:G 连通,G中只有两个奇度顶点(它们分别是欧拉通路的两个端点)。G有欧拉回路(G为欧拉图):G连通,G中均为偶度顶点。

3 有向图是否具有欧拉通路或回路的判定

D有欧拉通路:D连通,除两个顶点外,其余顶点的入度均等于出度,这两个特殊的顶点中,一个顶点的入度比出度大1,另一个顶点的入度比出度小1。D有欧拉回路(D为欧拉图):D连通,D中所有顶点的入度等于出度。

4 混合图。混合图也就是无向图与有向图的混合,即图中的边既有有向边也有无向边。

5 混合图欧拉回路

混合图欧拉回路用的是网络流。把该图的无向边随便定向,计算每个点的入度和出度。如果有某个点出入度之差为奇数,那么肯定不存在欧拉回路。因为欧拉回路要求每点入度 = 出度,也就是总度数为偶数,存在奇数度点必不能有欧拉回路。现在每个点入度和出度之差均为偶数。将这个偶数除以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连接的点,自然早在开始就已经满足入 = 出了。那么在网络流过程中,这些点属于“中间点”。我们知道中间点流量不允许有累积的,这样,进去多少就出来多少,反向之后,自然仍保持平衡。

Source Code

Problem: 1637  User: 1013101127 
Memory: 324K  Time: 110MS 
Language: C++  Result: Accepted 

Source Code 
#include<cstdio>
#include<queue>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<map>
#include<string>
#include <stdio.h>
#include <iostream>
#include <string.h>
#include<queue>
#include<cmath>
using namespace std;
const int inf=1<<30;
const int M=500,ME=3009;
const int INF=0x3f3fffff;
//******************************最小费用最大流模版(可以单独用来求最大流,输入的时候,cost=0就可以:适用于u->v,只要符合了流量限制,只要通过了就花费,还有一种是:u->v,每单位的流量必须花费对少费用(poj2159模板))
int Head[M],Next[ME],Num[ME],Flow[ME],Cap[ME],Cost[ME],vis[ME],Q[M],InQ[M],Len[M],pre_edge[M];
int top;

    void clear()
    {
        memset(Head,-1,sizeof(Head));
        memset(Flow,0,sizeof(Flow));
        memset(vis,0,sizeof(vis));
        top=0;
    }
    void addedge(int u,int v,int cap,int cost)
    {
        Next[top] = Head[u];
        Num[top] = v;
        Cap[top] = cap;
        Cost[top] = cost;
        Head[u] = top++;


        Next[top] = Head[v];
        Num[top] = u;
        Cap[top] = 0;
        Cost[top] = -cost;
        Head[v] = top++;
    }


    bool SPFA(int s,int t)
    {
        fill(Len,Len+M,INF);
        Len[s]=0;
        int head = -1,tail = -1,cur;
        Q[++head] = s;
        while(head != tail)
        {
            ++tail;
            if(tail >= M) tail = 0 ;
            cur = Q[tail];
            for(int i = Head[cur];i != -1;i = Next[i])
            {
                if(Cap[i]>Flow[i] && Len[Num[i]] > Len[cur] + Cost[i])
                {
                    Len[Num[i]] = Len[cur] + Cost[i];
                    pre_edge[Num[i]] = i;
                    if(!InQ[Num[i]])
                    {
                        InQ[Num[i]]=true;
                        ++head;
                        if(head >= M) head = 0;
                        Q[head] = Num[i];
                    }
                }
            }
            InQ[cur]=false;
        }
        return Len[t] != INF;
    }


    int solve(int s,int t)
    {
       int  ans= 0;
        while(SPFA(s,t))
        {
            int cur = t,minflow = INF;
            while(cur != s)
            {
                if(minflow > Cap[pre_edge[cur]]-Flow[pre_edge[cur]])
                    minflow = Cap[pre_edge[cur]]-Flow[pre_edge[cur]];
                cur = Num[pre_edge[cur] ^ 1];
            }
            cur = t ;
            ans+=minflow;
            while(cur != s)
            {
                Flow[pre_edge[cur]] += minflow;
                Flow[pre_edge[cur] ^ 1] -= minflow;
                vis[pre_edge[cur]]=1;
                cur = Num[pre_edge[cur] ^ 1];
            }
        }
        return ans;//最大流
        // int cost;//最小费用
        //for(int i=0;i<top;i++) //适用于u->v,只要符合了流量限制,只要通过了就花费,不管通过多少流量
        //{
              // if(Flow[i]>0)
              // cost+=Cost[i];
        //}
    }
//****************************************************************

int n,m;
int main()
{
    int cas;
    cin>>cas;
    int u,v,c;
    int ind[M],outd[M];
    while(cas--)
    {
        cin>>n>>m;
        clear();
        memset(ind,0,sizeof(ind));
        memset(outd,0,sizeof(outd));
        for(int i=0;i<m;i++)
        {
            cin>>u>>v>>c;
            if(c)
            {
                outd[u]++;ind[v]++;
            }
            else
            {
                outd[u]++;ind[v]++;
                addedge(u,v,1,0);
            }
        }
        int flag=1;
        for(int i=1;i<=n;i++)
        {
            if(abs(ind[i]-outd[i])%2==1)
            {
                flag=0;break;
            }
        }
        if(!flag)
        {cout<<"impossible"<<endl;continue;}
        int start=0;
        int end=n+1;
        int sum=0;
        for(int i=1;i<=n;i++)
        {
            if(ind[i]>outd[i])
            addedge(i,end,(ind[i]-outd[i])/2,0);
            else if(outd[i]>ind[i])
            {
              addedge(start,i,(outd[i]-ind[i])/2,0);
              sum+=(outd[i]-ind[i])/2;
            }
        }
        int ans=solve(start,end);
        //cout<<ans<<endl;
        if(sum==ans)
        cout<<"possible"<<endl;
        else
        cout<<"impossible"<<endl;
    }
    return 0;
}

抱歉!评论已关闭.