UVA10129欧拉路径

欧拉路径问题分为四种:
无向图的欧拉道路

无向图的欧拉回路

有向图的欧拉道路

有向图的欧拉回路

每一种的解决方式都是类似的

1》判断是否联通

2》判断是否满足有欧拉回路的条件

3》找出这条道路

对于有向图的连通问题可以将边看作是无向图,按照无向图来判断是否连通。

判断连通的方式有DFS和并查集,并查集以后再说,先来说说如何有DFS判断联通的问题

基本思路就是从一个点出发,如果可以一次dfs遍历到所有的点,那么就是连通的。

在这道题目中就是这样的。一次dfs后exist和vis数组相同

//先判断是否联通
#include<cstdio>
#include<cstring>
#include<vector>
#include<iostream>
using namespace std;

const int maxn = 30;
int G[maxn][maxn];//判断联通

int in_degree[maxn];
int out_degree[maxn];
int exist[maxn];
int vis[maxn];

void dfs(int x)
{
    vis[x] = 1;
    for(int i = 0;i<26;i++)
    {
        if(!vis[i]&&G[x][i])
            dfs(i);
    }
}

void print_vis_ex()
{
    for(int i=0;i<26;i++)
    {
        printf("%d ",exist[i]);
    }
    printf("\n");
    for(int i=0;i<26;i++)
    {
        printf("%d ",vis[i]);
    }
    printf("\n");
}
bool connect()
{
    for(int i = 0;i<26;i++)
    {
        if(!vis[i]&&exist[i])
        {
//printf("%d\n",i);
            dfs(i);
            break;//这个时候vis和exist应该是一样的,如果是联通的话
        }
    }
//print_vis_ex();
    for(int i=0;i<26;i++)
    {
        if(vis[i]!=exist[i])
            return false;
    }
    return true;
}

bool euler()
{//入度全部等于出度,或者有一个入度大于出度1,另一个出度大于入度1
    int cnt = 0,d;
    for(int pos = 0;pos < 26;pos++)
    {
        if(in_degree[pos]!=out_degree[pos])
        {
            d = in_degree[pos]-out_degree[pos];
            cnt++;
        }
    }
    if(cnt==0||(cnt==2&&(d==1||d==-1)))
        return true;
    return false;
}

void print_G()
{
    for(int i= 0;i<26;i++)
    {
        for(int j = 0;j<26;j++)
        {
            printf("%d ",G[i][j]);
        }
        printf("\n");
    }
    printf("\n\n");
}

int main()
{
#ifdef local
    freopen("input.txt","r",stdin);
    freopen("out.txt","w",stdout);
#endif
    int kase;
    scanf("%d",&kase);
    for(int i=0;i<kase;i++)
    {
        memset(in_degree,0,sizeof(in_degree));
        memset(out_degree,0,sizeof(out_degree));
        memset(G,0,sizeof(G));
        memset(exist,0,sizeof(G));
        memset(vis,0,sizeof(vis));
        int x;
        scanf("%d",&x);
        for(int j=0;j<x;j++)
        {
            string s;
            cin>>s;
            out_degree[s[0]-'a']++;
            in_degree[s[s.size()-1]-'a']++;
            G[s[0]-'a'][s[s.size()-1]-'a']=1;
            G[s[s.size()-1]-'a'][s[0]-'a']=1;
            exist[s[0]-'a']=1;
            exist[s[s.size()-1]-'a']=1;
        }
//print_G();
        bool flag=false;
        if(connect())
        {
//printf("ccc\n");
            if(euler())
                flag = true;
        }
        if(flag)
        {
            printf("Ordering is possible.\n");
        }
        else
        {
            printf("The door cannot be opened.\n");
        }
    }
    return 0;

}

判断完是否连通后,就需要去判断是否满足拥有欧拉路径的条件

无向图有欧拉道路的条件是,只有两个点的度数是奇数

无向图有欧拉回路的条件是,度数全部都是偶数

有向图有欧拉回路的条件是,每个点的出度和入度相等

有向图有欧拉道路的条件是,只有两个点的出度和入度不相同,而且一个是入度多1,一个是出度多1

在本题中,由于是有向图,那么只要它可以满足后两个条件中的任意一个就可以了。

判断思路是这样的,判断每个出度和入度,记录不相等的次数,和其中一次的差,如果不想等的次数是0,或者不相等的次数时2,而且其中一次是1或者-1(如果有一次是1,那么由于各点出度和入度的和一定是一样的,所有另一个一定是-1);

下面重点是如何寻找欧拉路径

void euler(int u)
{
    for(int i= 0;i<n;i++)
    {
        if(G[u][i]&&vis[u][i])
        {
            vis[u][i] = vis[i][u] = 1;
            euler(i);
        }
    }
    V.push_back(u);
}

这段代码展示的就是寻找无向图的欧拉道路的情况,下面来解释一下:

想要完全理解这段代码,需要去理解DFS的运行机制,尤其是它是如何回溯返回的,分析就不说了,太麻烦;v中保存的就是欧拉路径中经过的点。

上面vis[][]需要解释一下,因为点可以重复访问,所以不能对点设置vis,必须对边设置vis。

当无向图变为有向图的时候,将上面的vis该为一个即可。dfs()的参数是起点。

 

转载于:https://www.cnblogs.com/TorettoRui/p/10443722.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值