`
yzmduncan
  • 浏览: 330327 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
文章分类
社区版块
存档分类
最新评论

网络流之--混合图的欧拉回路

阅读更多

基础知识

    欧拉回路是图G中的一个回路,经过每条边有且仅一次,称该回路为欧拉回路。具有欧拉回路的图称为欧拉图,简称E图。

    无向图中存在欧拉回路的条件:每个点的度数均为偶数。

    有向图中存在欧拉回路的条件:每个点的入度=出度。

    欧拉路径比欧拉回路要求少一点:

    无向图中存在欧拉路径的条件:每个点的度数均为偶数或者有且仅有2个度数为奇数的点。

    有向图中存在欧拉路径的条件:除了2个点外,其余的点入度=出度,且在这2个点中,一个点的入度比出度大1,另一个出度比入度大1。

     欧拉路径的输出:经典的套圈算法。

 

    下面来重点讲讲混合图的欧拉回路问题。

    混合图就是边集中有有向边和无向边同时存在。这时候需要用网络流建模求解。

    建模:

    把该图的无向边随便定向,计算每个点的入度和出度。如果有某个点出入度之差为奇数,那么肯定不存在欧拉回路。 因为欧拉回路要求每点入度 = 出度,也就是总度数为偶数,存在奇数度点必不能有欧拉回路。

    好了,现在每个点入度和出度之差均为偶数。那么将这个偶数除以2,得x。也就是说,对于每一个点,只要将x条边改变方向(入>出就是变入,出>入就是变出),就能保证出 = 入。如果每个点都是出 = 入,那么很明显,该图就存在欧拉回路。

    现在的问题就变成了:我该改变哪些边,可以让每个点出 = 入?构造网络流模型。

    首先,有向边是不能改变方向的,要之无用,删。一开始不是把无向边定向了吗?定的是什么向,就把网络构建成什么样,边长容量上限1。另新建s和t。对于入 > 出的点u,连接边(u, t)、容量为x,对于出 > 入的点v,连接边(s, v),容量为x(注意对不同的点x不同)。
    之后,察看从S发出的所有边是否满流。有就是能有欧拉回路,没有就是没有。欧拉回路是哪个?察看流值分配,将所有流量非 0(上限是1,流值不是0就是1)的边反向,就能得到每点入度 = 出度的欧拉图。 
    由于是满流,所以每个入 > 出的点,都有x条边进来,将这些进来的边反向,OK,入 = 出了。对于出 > 入的点亦然。那么,没和s、t连接的点怎么办?和s连接的条件是出 > 入,和t连接的条件是入 > 出,那么这个既没和s也没和t连接的点,自然早在开始就已经满足入 = 出了。那么在网络流过程中,这些点属于“中间点”。我们知道中间点流量不允许有累积的,这样,进去多少就出来多少,反向之后,自然仍保持平衡。
    所以,就这样,混合图欧拉回路问题,解了。

 

例:HDU3472

题意:给出一些单词,其中有些单词反转之后也是有意义的单词,问是否能将所有单词首尾相连,每个单词用1次且仅用1次。

解:这题是混合路的欧拉路径问题。

    1.首先判断图的连通性,若不连通,无解。

    2.然后任意定向无向边,计算每个点i的入度和出度之差deg[i]。若deg[i]为奇数,无解。

    3.设立源点s和汇点t,若某点i入度<出度,连边(s,i,-deg[i]/2),若入度>出度,连边(i,t,deg[i]/2);对于任意定向的无向边(i,j,1)。

    4.若有两个度数为奇数的点,假设存在欧拉路径,添加一条容量为1的边,构成欧拉回路,不影响结果。若全为偶数,直接最大流。

    5.若从S发出的边全部满流,证明存在欧拉回路(路径),否则不存在。

    ps:若要求输出路径,将网络中有(无)流量的边反向,加上原图的有向边,用套圈算法即可。

 

/*
混合图的欧拉回路
    建模:将有向边删除,给无向边任意定向,计算每个点的入度与出入之差,若为奇数,肯定无解;
    若为偶数,若图中存在边(i,j),那么设容量为1;对于每个点i,若deg[i]<0,从s连边道i,容量为-deg[i]/2,若>0,连边(i,t,deg[i]/2)
    求最大流,如果所有从s出发的弧都满载,则存在欧拉回路,否则不存在。
    把图中所有有(无)流量的弧都反向,把原图中的有向边加上,就构成了一个欧拉回路。
*/
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int INF = 0x7fffffff;
const int maxv = 30;
const int maxe = 5000;
int n;
struct Edge
{
    int v;
    int next;
    int flow;
};
Edge e[maxe];
int head[maxv],edgeNum;
int now[maxv],d[maxv],vh[maxv],pre[maxv],preh[maxv];
int deg[30];
bool used[30];
int p[30],rank[30];

void addEdge(int a,int b,int c)
{
    e[edgeNum].v = b;
    e[edgeNum].flow = c;
    e[edgeNum].next = head[a];
    head[a] = edgeNum++;
    e[edgeNum].v = a;
    e[edgeNum].flow = 0;
    e[edgeNum].next = head[b];
    head[b] = edgeNum++;
}

void Init()
{
    edgeNum = 0;
    memset(head,-1,sizeof(head));
    memset(d,0,sizeof(d));
}

int sap(int s,int t,int n)       //源点,汇点,结点总数
{
    int i,x,y;
    int f,ans = 0;
    for(i = 0; i < n; i++)
        now[i] = head[i];
    vh[0] = n;
    x = s;
    while(d[s] < n)
    {
        for(i = now[x]; i != -1; i = e[i].next)
            if(e[i].flow > 0 && d[y=e[i].v] + 1 == d[x])
                break;
            if(i != -1)
            {
                now[x] = preh[y] = i;
                pre[y] = x;
                if((x=y) == t)
                {
                    for(f = INF,i=t; i != s; i = pre[i])
                        if(e[preh[i]].flow < f)
                            f = e[preh[i]].flow;
                    ans += f;
                    do
                    {
                        e[preh[x]].flow -= f;
                        e[preh[x]^1].flow += f;
                        x = pre[x];
                    }while(x!=s);
                }
            }
            else
            {
                if(!--vh[d[x]])
                    break;
                d[x] = n;
                for(i=now[x]=head[x]; i != -1; i = e[i].next)
                {
                    if(e[i].flow > 0 && d[x] > d[e[i].v] + 1)
                    {
                        now[x] = i;
                        d[x] = d[e[i].v] + 1;
                    }
                }
                ++vh[d[x]];
                if(x != s)
                    x = pre[x];
            }
    }
    return ans;
}

void makeSet()
{
    for(int i = 0; i < 26; i++)
    {
        p[i] = i;
        rank[i] = 0;
    }
}

int findSet(int x)
{
    if(x != p[x])
        p[x] = findSet(p[x]);
    return p[x];
}

void Union(int x, int y)
{
    x = findSet(x);
    y = findSet(y);
    if(x == y)
        return;
    if(rank[x] > rank[y])
        p[y] = x;
    else
    {
        p[x] = y;
        if(rank[x] == rank[y])
            rank[y]++;
    }
}

int main()
{
    int i,j,k;
    int t,T;
    char wd[22];
    scanf("%d",&T);
    for(t = 1; t <= T; t++)
    {
        scanf("%d",&n);
        Init();
        makeSet();
        memset(deg,0,sizeof(deg));
        memset(used,0,sizeof(used));
        bool flag = true;
        for(i = 1; i <= n; i++)
        {
            scanf("%s %d",wd,&k);
            int len = strlen(wd);
            int a = wd[0]-'a';
            int b = wd[len-1]-'a';
            used[a] = true;
            used[b] = true;
            deg[a]--;
            deg[b]++;
            if(k == 1)
                addEdge(a,b,1);
            Union(a,b);
        }
        int start = 26;
        int end = 27;
        for(i = 0; i < 26 && flag; i++)                 //连通性
        {
            for(j = i+1; j < 26 && flag; j++)
            {
                if(used[i] && used[j] && findSet(i)!=findSet(j))
                    flag = false;
            }
        }
        int tmpt = 0;
        int v1=-1,v2=-1;
        for(i = 0; i < 26 && flag; i++)                 //度数为奇数的点为0个或者2个
        {
            if(deg[i]%2 == 1 || deg[i]%2 == -1)
            {
                tmpt++;
                if(deg[i] < 0)  //起点
                    v1 = i;
                if(deg[i] > 0)  //终点
                    v2 = i;
            }
        }
        if(tmpt==0 || (tmpt==2&&v1!=-1&&v2!=-1))
        {
            if(tmpt == 2)
                addEdge(v2,v1,1);
        }
        else
            flag = false;
        int sum = 0;
        for(i = 0; i < 26 && flag; i++)
        {
            if(deg[i] < 0)
            {
                addEdge(start,i,-deg[i]/2);
                sum += -deg[i]/2;
            }
            else
                addEdge(i,end,deg[i]/2);
        }
        if(!flag || sum != sap(start,end,end+1))
            printf("Case %d: Poor boy!\n",t);
        else
            printf("Case %d: Well done!\n",t);
    }
    return 0;
}

 

 

 

分享到:
评论

相关推荐

    网络流建模_周尚彦.pdf

    混合图的欧拉回路Definition(欧拉回路) 每条边经过且仅经过一次的回路。 给出一个既存在有向边,又存在无向边的图,问是否存在欧拉回路。 欧拉回路的判断方法:每个点的入度等于出度连通先给无向边任意定向,再...

    欧拉路径等

    三、混合图:欧拉路径首先,我们用上文所说的方法判断该图是否存在欧拉回路,如果存在,欧拉路径一定存在。如果欧拉回路不存在,那么我们枚举欧拉路径的起点和终点,连接一条无向边,然后再用最大流判断是否存在欧拉...

    poj图论题目汇总

    #### 1637 *Sightseeing tour - 混合图欧拉回路-网络流 - **知识点**:欧拉回路和网络流算法。 #### 1716 Integer Intervals - 差分约束 - **知识点**:差分约束系统。 #### 1724 *ROADS - 最短路-拆点 - **...

    图论与网络 北京大学数学系

    - **欧拉图(Eulerian graph)**:具有欧拉回路的图。 #### 八、树图与最小生成树 - **树图(tree)**:无向连通图,不含回路,且任意两个节点之间恰好有一条路径。 - **最小生成树(minimum spanning tree)**:在一个带...

    总模板_lsy_WF[2015-04-16]1

    3. **混合欧拉路欧拉回路的判断-&gt;网络流模型**:利用网络流的方法来判断一个图是否存在欧拉回路,通过建立源点和汇点,使得每个边都可以作为一条容量为1的有向边,然后看是否能实现从源点到汇点的满流。 **四、RMQ...

    图论模板详细

    - 混合图欧拉回路判定:用于判定一个图(可以是有向的,也可以是无向的)是否存在欧拉回路,即是否存在一条路径经过图中每一条边恰好一次并回到起点。 - 上下界最大流和最小流问题:涉及在有上下界约束的网络流...

    天津大学 ACM模板

    - 混合图的欧拉回路:在含有两种边(有向和无向)的图中寻找欧拉回路。 此外,还提到了计算几何的相关知识点: - 直线和线段的转换:将直线一般式与两点式互相转换。 - 点的旋转和反射:实现点在平面上的旋转和反射...

    ACM_算法模板集.pdf

    - **混合图欧拉回路 (Eulerian Circuit in Mixed Graphs)** - 定义:在包含边和弧的混合图中寻找欧拉回路。 - **无源汇上下界网络流 (Network Flow with Lower and Upper Bounds)** - 定义:在网络流问题中考虑边...

    networkx_reference.pdf

    - **欧拉图算法**:判断图是否为欧拉图,并寻找欧拉路径或回路。 - **流算法**:解决图中的流问题,如最大流最小割。 - **图哈希算法**:为图生成唯一的标识符。 - **图形度序列算法**:检查给定的度序列是否可图化...

    上海交通大学ACM算法模板

    30. 混合图欧拉回路 31. 无源汇上下界网络流 32. 二分图最小点权覆盖 33. 带约束的轨道计数(Burnside引理) 34. 三分法求函数波峰 35. 单词计数,矩阵乘法 36. 字符串和数值hash 37. 滚动队列,前向星表示法 38. 最小...

    ACM 算法模板集

    30. 混合图欧拉回路 31. 无源汇上下界网络流 32. 二分图最小点权覆盖 33. 带约束的轨道计数(Burnside引理) 34. 三分法求函数波峰 35. 单词计数,矩阵乘法 36. 字符串和数值hash 37. 滚动队列,前向星表示法 38. 最小...

    图论(课件)~~~~~~~~~

    图论是数学的一个分支,专门...它不仅提供了描述和分析复杂关系的数学模型,而且在算法设计中扮演了重要角色,如最短路径问题、网络流问题、匹配问题等。图论的深入学习可以帮助我们理解和解决现实世界中的诸多问题。

    ACM_算法模板

    28. **混合图欧拉回路**: - 混合图中的欧拉路径问题。 29. **无源汇上下界网络流**: - 一种特殊的网络流问题。 30. **二分图最小点权覆盖**: - 选择权重最小的一组点覆盖所有边。 31. **带约束的轨道计数**: ...

    ACM算法模板集史上最完整收藏版

    28. **混合图欧拉回路**: - 处理包含有向边和无向边的混合图。 - 在图论和网络设计中有着重要应用。 29. **无源汇上下界网络流**: - 在某些特定条件下求解最大流问题。 - 在物流和资源分配问题中有着重要应用...

    图论总结 by Amber.doc

    - **欧拉路径/回路**:图中所有边恰好使用一次的路径或回路,根据图的类型(无向、有向、混合、无权、有权)有不同的条件。 - **哈密顿回路**:图中经过所有顶点一次并返回起点的回路,旅行商问题即为寻找具有最小...

    图论基础模板

    欧拉路是指在图中通过每条边恰好一次的路径,而欧拉回路则要求起点和终点相同。混合欧拉路问题可以通过最大流算法来解决。 6. 二分图: 二分图是指图的顶点集可以分割为两个互不相交的子集,图中的每条边连接的两...

    图论总结by amber

    1.6.3. 网络流 Flow network 1.6.3.1. 最大流 Maximum flow 1.6.3.1.1. 基本算法 Basic algorithms 1.6.3.1.1.1. Ford-Fulkerson method 1.6.3.1.1.1.1. Edmonds-Karp algorithm 1.6.3.1.1.1.1.1. Minimum length ...

    上海交通大学ACM算法模板gai.pdf

    30. 混合图欧拉回路:处理混合图(有向和无向边混合)的欧拉路径。 31. 无源汇上下界网络流:在网络流问题中处理无源汇的情况。 32. 二分图最小点权覆盖:寻找二分图中最小点集使得所有边被覆盖。 33. 带约束的轨道...

Global site tag (gtag.js) - Google Analytics