[转] 欧拉路径和欧拉回路及其应用

概念转自https://blog.csdn.net/qq_34454069/article/details/77779300

欧拉路径:在一个图中,从i点出发,能将每个边遍历一次最终达到j点的一条路径
欧拉回路:i=j时的欧拉路径

无向图

欧拉回路:在无向图中,只要每个点的度数均为偶数,那么必定存在欧拉回路。因为每个点的度是偶数,意味着总有成对的入边和出边,则不会出现卡在一个节点的情况。
这里写图片描述

欧拉路径:有且仅有两个点的度数为奇数,那么存在从其中一个点到另一个点的欧拉路径。
这里写图片描述

有向图

欧拉回路:所有点的入度等于出度,就存在一条欧拉回路。类似于无向图,每个节点都有成对的入边和出边,那么必定存在欧拉回路

欧拉路径:至多一个点的出度 = 入度 + 1 (起点) , 之多一个点的 入度 = 出度 + 1 (终点) 。

至此判断一个图是否存在欧拉回路和欧拉路径已经可以完成。
接下来是知道存在的条件下找出路径。也就是常规的dfs把每条边走一遍。但是注意,第一个栈底的是无路可走的节点,我们在按照栈输出就行,也就是逆序输出,原因如下:

例如 1 - > 2 -> (3 -> 2 ) -> 1 这是个存在环的回路, 但是也满足欧拉路径的要求。
我们在dfs时可以看做每条边都有概率执行, 因此我们会得到这个dfs序: 1 -> 2 -> 1 (然后回溯返回到2) -> 3 - > 2。 顺序输出的话,把一些行不通的路径也输出了 。逆序输出则保证了栈底的必须是第一个无路可走的节点,也就是终点。

// 有可能两个点之间存在多条边,那么可以用vis[x][i] -- ,减一次走一次
void dfs(int x)
{
    for(int i=0; i<a[x].size(); i++)
    {
        int v = a[x][i];
        if(vis[x][v]==0)
        {
            vis[x][v]=1;
            //delete(a[x][i],x);无向图要加这句
            dfs(v);
            path.push(x -> v);//存储路径上的边
            cnt++;
        }
    }

    ans.push(x);//存储路径上的点
}

应用:

1、Uva 10054 The Necklace
题意:给你n个珠子,一个珠子分为两半有两种颜色,用1到50来表示50种不同的颜色。把这些珠子串起来,两个紧挨着的珠子要满足一个条件就是接触的那部分颜色要相同

例如(1,2)(2,4),两个珠子的接触部分颜色相同都为2。当然,因为珠子最后是连成环的,第一个珠子和最后一个珠子也会接触,也要买满足这个条件

先输入T,有T组数据

输入n,有n个珠子

下面n行每行两个数字表示这个珠子的两个颜色,然后问你能不能连成一条链,能的话输出任意一种连接情况即可,不能的话输出失败.

思路:

给定的珠子上的两个颜色,看出无向图两个点连上一条边。题目转化成无向图的欧拉回路是否存在,存在即输出。
详细的可以看这里https://www.cnblogs.com/scau20110726/archive/2012/11/09/2762371.html

代码:
#include <iostream>
#include <bits/stdc++.h>

using namespace std;

vector<int>G[100];
int vis[100][100];
int d[100];
void dfs(int x)
{
    for(int i=0; i<G[x].size(); i++)
    {
        int v = G[x][i];
        if(vis[x][v]>0)
        {
            vis[x][v]--;
            vis[v][x]--;
            dfs(G[x][i]);
            printf("%d %d\n",v,x);

        }
    }

}

int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    while(m--)
    {
        int a,b;
        cin>>a>>b;
        G[a].push_back(b);
        d[a]++;
        d[b]++;
        vis[a][b] ++;
        vis[b][a] ++;
    }
    for(int i=1; i<=n; i++)
        if(d[i]%2)
        {
            puts("some beads may be lost\n");
            return 0;
        }

    dfs(1);

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值