无向图与有向图判定欧拉道路与欧拉回路的方法

那年仲夏 提交于 2020-05-01 11:32:48

欧拉道路:

从无向图中的一个节点出发走一条道路,每条边恰好经过一次,这样的线路成为欧拉道路。

下面给出欧拉道路的判定方法:

有向图:

图必须是连通的,而且最多只能有两个点入度不等于出度,而且这两个点其中一个点的入度+1=出度,另一个点的出度+1=入度,如果有的点出度!=入度&&出度与入度的绝对值差还不等于1,则这个图不是欧拉道路。

无向图:

图必须是连通的,而且最多有两个奇度点,则是欧拉道路。

判定图连通的方法:

无向图用dfs访问,看看点是否全部被访问。

有向图先转化为无向图,然后再用dfs判定。

欧拉回路:

如果一个回路是欧拉路径,则称为欧拉回路。

下面给出欧拉回路的判定方法:

有向图:

图连通,且所有顶点的入度等于出度。

无向图:

图连通,且没有奇度点。

下面给出一个欧拉道路的例题:

题目为UVa的10129:

题目:

Some of the secret doors contain a very interesting word puzzle. The team of archaeologists has to solve it to open that doors. Because there is no other way to open the doors, the puzzle is very important for us.

There is a large number of magnetic plates on every door. Every plate has one word written on it. The plates must be arranged into a sequence in such a way that every word begins with the same letter as the previous word ends. For example, the word ``acm'' can be followed by the word ``motorola''. Your task is to write a computer program that will read the list of words and determine whether it is possible to arrange all of the plates in a sequence (according to the given rule) and consequently to open the door.

题目大意翻译:


有一些秘密的门包含着非常有趣的单词迷题, 考古学家队伍必须解决它们才能够打开大门。 因为没有其他方法能偶打开这些门, 所以解决那些迷题对我们非常重要。


在每个门上有很多个有磁力的盘子,盘子上面写着单词。 必须重新移动放置这些盘子,让它们形成一个队列:队列中,除了第一个单词,每个单词的开头和上一个单词的结尾字母

一样。例如, motorola的后面可以接上acm。


你的任务是写一个程序, 读入一系列单词,然后计算确定它们是否有可能被排成这样的队列。


样例输入:

3
2
acm
ibm
3
acm
malform
mouse
2
ok
ok


样例输出:

The door cannot be opened.
Ordering is possible.
The door cannot be opened.

思路:

可以把首尾字母看做节点,把单词看成有向边,构造有向图,如果有解,当且仅当图中有欧拉路径。

上面说到了有向图的欧拉路径的判定方法:1.将有向图转化为无向图判定连通,2.看入度和出度的关系。

代码如下:

#include <cstdio>
#include <cstring>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=30;
int n,t;
int in[30],out[30];
int edge[maxn][maxn];
int vis[maxn];
//dfs判定连通
void dfs (int x)
{
    vis[x]=1;
    for (int i=0;i<26;i++)
    {
        if(edge[x][i]&&!vis[i])
        {
            dfs(i);
        }
    }
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        memset (in,0,sizeof(in));
        memset (out,0,sizeof(out));
        memset (edge,0,sizeof(edge));
        memset (vis,0,sizeof(vis));
        scanf("%d",&n);
        for (int i=0;i<n;i++)
        {
            char x[1005];
            scanf("%s",x);
            int len=strlen(x);
            //构造无向图
            edge[x[0]-'a'][x[len-1]-'a']++;
            edge[x[len-1]-'a'][x[0]-'a']++;
            //构造有向图的入度和出度关系
            out[x[0]-'a']++;
            in[x[len-1]-'a']++;
        }
        int edge=0,num1=0,num2=0,Flag=1;
        //根据入度出度判定是否满足条件
        for (int i=0;i<=26;i++)
        {
            if(in[i]!=out[i])
            {
                if(in[i]-out[i]==1) num1++;
                else if(in[i]-out[i]==-1) num2++;
                else
                {
                    Flag=0;
                    break;
                }
            }
        }
        if(num1&&num2&&num1+num2>2) Flag=0;
        if(Flag==0)
        {
            printf("The door cannot be opened.\n");
            continue;
        }
        //判定连通
        for (int i=0;i<=26;i++)
        {
            if(out[i]||in[i])
            {
                dfs(i);
                break;
            }
        }
        int flag=0;
        for (int i=0;i<=26;i++)
        {
            if(in[i]&&!vis[i]){flag=1; break;}
            if(out[i]&&!vis[i]){flag=1;break;}
        }
        if(flag==0) printf("Ordering is possible.\n");
        else printf("The door cannot be opened.\n");
    }
    return 0;
}



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!