UVA - 10129(用DFS判断连通性euler)

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.
Input
The input consists of T test cases. The number of them (T) is given on the first line of the input file.
Each test case begins with a line containing a single integer number N that indicates the number of
plates (1 ≤ N ≤ 100000). Then exactly N lines follow, each containing a single word. Each word
contains at least two and at most 1000 lowercase characters, that means only letters ‘a’ through ‘z’ will
appear in the word. The same word may appear several times in the list.
Output
Your program has to determine whether it is possible to arrange all the plates in a sequence such that
the first letter of each word is equal to the last letter of the previous word. All the plates from the
list must be used, each exactly once. The words mentioned several times must be used that number of
times.
If there exists such an ordering of plates, your program should print the sentence ‘Ordering is
possible.’. Otherwise, output the sentence ‘The door cannot be opened.’
Sample Input
3
2
acm
ibm
3
acm
malform
mouse
2
ok
ok
Sample Output
The door cannot be opened.
Ordering is possible.
The door cannot be opened.

题意:给你一串单词,问你这些单词能否首位相连,连成一个长串。连接规则是上一个单词的最后一个字母要与下一个单词的第一个字母相同。

题解:把每一个单词首字母与尾字母当成一个节点,这道题就成了Euler连通图的问题。这道题的图是有向图,所以一笔画问题,也就是题中所要求的问题要考察两方面内容,如果两方面内容都为真,那么就成立,就为真,只要有一个不成立,则为假。一方面是要入度与出度最多相差1,而且最多是2个点的入度与出度有差,另一方面是图要连通,也就是,从一个点(可以是任意一个节点)开始dfs,要能把所有的点都覆盖到。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <map>
#include <queue>
#include <cmath>

using namespace std;
const int maxn = 100000 + 5;
const int maxm = 1000 + 5;
int g[maxm][maxm], vis[maxm], in[maxm], out[maxm], flag, ID, flag1;
char word[maxn];
map<char, int> IDcache;

//查连通,如果一个图是连通的,那么从一个节点开始访问,采用深度优先或者广度优先对它进行遍历,那么必定能够访问完所有的节点。
void euler(int u)
{
    vis[u] = 1;//u已经访问过
    for (int v = 0; v < ID; v++) {
        if (g[u][v] && !vis[v]) {
            euler (v);
        }
    }
}

//输入函数
void scan(int n)
{
    while (n--) {
        cin >> word;
        if (!IDcache.count(word[0])) {
            IDcache[word[0]] = ID++;
        }
        int l = strlen (word);
        if (!IDcache.count(word[l - 1])) {
            IDcache[word[l - 1]] = ID++;
        }
        g[IDcache[word[0]]][IDcache[word[l - 1]]]++;
        in[IDcache[word[l - 1]]]++;
        out[IDcache[word[0]]]++;
    }
}

//输出函数
void print()
{
    if (flag) {
        printf ("Ordering is possible.\n");
    } else {
        printf ("The door cannot be opened.\n");
    }
}

//初始化函数
void init()
{
    memset (g, 0, sizeof(g));
    memset (vis, 0, sizeof(vis));
    memset(in, 0, sizeof(in));
    memset(out, 0, sizeof(out));
    IDcache.clear();
    ID = 0;
    flag = 1;//是否连通,1为连,0为不连
    flag1 = 1;
}

//判断是否连通
void is_connect()
{
    if (flag) {
        //从每一个字母开头试一次,只要有一个连通,那就可以,如果一个都不连通,那就不可以
        for (int i = 0; i < ID; i++) {
            memset (vis, 0, sizeof(vis));
            flag1 = 1;
            euler (i);
            for (int j = 0; j < ID; j++) {
                if (vis[j] == 0) flag1 = 0;
            }
            if (flag1 == 1) break;
        }
        if (flag1 == 0) flag = 0;
    }
}

//找初始节点(数度),用euler函数判断连通
void degree()
{
    int num1=0, num2=0;
    for (int i = 0; i < ID; i++) {
        if (!flag) break;
        if (in[i] != out[i]) {//如果入度不等于出度
            if (in[i] == out[i] + 1) {
                ++num1;
            }
            else if (out[i] == in[i] + 1) {
                ++num2;
            }
            else {//入度与出度差大于1
                flag = 0;
                break;
            }
        }
    }
    if(num1 && num2 && num1 + num2 > 2) flag = 0;//多于2个奇点
}

int main()
{
    #ifndef ONLINE_JUDGE
    freopen ("in.txt", "r", stdin);
    #endif // ONLINE_JUDGE
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        init ();
        scan (n);
        degree ();
        is_connect ();
        print ();
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值