UVA10129-欧拉回路-DFS

第一次写博客,以前一直没有总结过,现在开始对自己学的东西做一些记录吧,方便以后复习或者就当作留个脚印。

笔者目前大一,水平弱弱弱…有不正确的地方或者可以改进的地方还望指出。

找伙伴,有想一起学习的朋友可以一起交流交流。email:   zpengst@outlook.com

题目链接:https://vjudge.net/problem/UVA-10129

题目大意:输入n个单词,判断是否能把所有单词连接成一个串,使得每个单词首字母与前一个单词尾字母相同。

思路:

1:把每个单词看作一座桥,二十六个英文字母看作节点,保存成无向图,还要记录每个节点出度入度。

2:判断整个有向图的奇点数是否大于2,大于2则不存在欧拉道路,存在则走第三步。

3:判断图的连通性,笔者目前只会用DFS(并查集还没学),看作无向图(稍微提高效率)。若连通则存在欧拉道路。

注意:

思路讲起来简洁,然而每次实现都会遇到各种问题。(笔者太弱了)

若奇点数为2,判断连通性的时候一定要注意起点是出度大于入度的那个节点。(如果要打印路径)

若奇点数为0,(容易忽略)一定要找一个存在桥的节点作为起点。

代码:

话不多说,直接上AC代码。看了下各路大神的代码,都这么短!!!都不好意思贴上来了。

不太想写注释了,代码如下。

#include<iostream>
#include<string>
#include<cstring>
#include<cstdlib>
using namespace std;

bool G[26][26];
int out_cnt[26],in_cnt[26];

void dfs(int in)
{
    for(int i=0; i<26; ++i)
    {
        if(G[in][i])
        {
            G[in][i]=G[i][in]=false;
            dfs(i);
        }
    }
}
bool is_cncted(int in)
{
    dfs(in);
    for(int i=0; i<26; ++i)
        for(int j=0; j<26; ++j)
            if(G[i][j])
                return false;
    return true;
}
int main()
{
    int n;
    cin>>n;
    while(n--)
    {
        memset(G,0,sizeof(G));
        memset(out_cnt,0,sizeof(out_cnt));
        memset(in_cnt,0,sizeof(in_cnt));

        int t;
        cin>>t;
        string s;

        while(t--)
        {
            cin>>s;
            G[*s.begin()-'a'][*(s.end()-1)-'a']=
                G[*(s.end()-1)-'a'][*s.begin()-'a']=1;
            out_cnt[*s.begin()-'a']++;
            in_cnt[*(s.end()-1)-'a']++;
        }

        int sp_in=0,sp_cnt=0,flag=1;

        for(int i=0; i<26; ++i)
            if(in_cnt[i]!=out_cnt[i])
                if(++sp_cnt>2||abs(in_cnt[i]-out_cnt[i])!=1)
                {
                    flag=0;
                    break;
                }
                else if(sp_cnt==1)
                    sp_in=i;
                else if(in_cnt[sp_in]-out_cnt[sp_in]+in_cnt[i]-out_cnt[i])
                {
                    flag=0;
                    break;
                }

        if(flag)
            for(int i=0; i<26; ++i)
                if(out_cnt[i])
                {
                    if(!is_cncted(i))
                        flag=0;
                    break;
                }
        if(flag)
            cout<<"Ordering is possible."<<endl;
        else
            cout<<"The door cannot be opened."<<endl;
    }
    return 0;
}

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值