hdu 1116 Play on Words 有向图欧拉回路存在与否的判定

缘起

判断有向图是否存在欧拉回路,关于欧拉回路的定义以及判定存在性参见【1】

分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
判断n个单词是否可以相连成一条链或一个环,两个单词可以相连的条件是前一个单词的最后一个字母和后一个单词的
第一个字母一样。

【输入】
多样例,样例数在第一行给出. 每个样例以单词数量N(1 <= N <= 100000)开头. 然后N行,每行包含一个单词
每个单词至多1000个小写字母. 注意, 可能一个单词出现多次.

【输出】
按照样例输出

【样例输入】
3
2
acm
ibm
3
acm
malform
mouse
2
ok
ok

【样例输出】
The door cannot be opened.
Ordering is possible.
The door cannot be opened.

【限制】
5s

将每个英文字母视作是图的顶点(不超过30个). 则每读入一个单词,就建立了一条从单词首字母到尾字母的弧 . 所以这就构成一个不超过26个顶点的有向图. 其实就是要判断此有向图是否存在欧拉回路或者欧拉路径. 根据【1】

有根图存在欧拉回路的充要条件是所有顶点的出度=入度

有根图存在欧拉路径的重要条件是一个顶点的出度比入度多1作为欧拉路径的起点,存在一个顶点的出度比入度少1作为欧拉路径的终点, 而其余点的出度=入度.

所以本题的算法就显然了,通过并查集看看是不是有根图. 然后统计出度入度即可.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
//#include "stdafx.h"

#include <stdio.h>
#include <string.h>
//#define LOCAL

int n, cnt,f[30], indeg[30], outdeg[30];
char c[1005];
bool used[30]; // 那个字母用过了

int getf(int i)
{
return f[i]==i?i:f[i]=getf(f[i]);
}

void merge(int i, int j) // i->j弧
{
int fi = getf(i), fj = getf(j);
if (fi!=fj)
{
f[fj] = fi;
}
}

bool ok()
{
int sum = 0,p=0,q=0, pi,qi;
for (int i =1; i<30; i++)
{
if (used[i] && f[i]==i)
{
sum++;
}
}
if (sum>1) // 无根
{
return false;
}
for (int i = 1; i<30; i++) // 统计出度入度
{
indeg[i]-=outdeg[i];
if (indeg[i]>0)
{
p++;
if (p>1)
{
return false;
}
pi = i;
}
else if (indeg[i]<0)
{
q++;
if (q>1)
{
return false;
}
qi = i;
}
}
if (p&&q) // 如果都不是0的话, 必须要一个是1一个是-1
{
return indeg[pi]==1 && indeg[qi]==-1;
}
return !p&&!q; // 必须要都是0才行了
}

int main()
{
#ifdef LOCAL
freopen("d:\\data.in", "r", stdin);
//freopen("d:\\my.out", "w", stdout);
#endif
int kase;
scanf("%d", &kase);
while(kase--)
{
memset(used, 0, sizeof(used));
memset(indeg, 0, sizeof(indeg));
memset(outdeg, 0, sizeof(outdeg));
cnt = 0;
for (int i = 1; i<30; i++)
{
f[i] =i;
}
scanf("%d", &n);
getchar(); // 吸收多余换行符
while(n--)
{
gets(c);
int len = strlen(c);
used[c[0]-'a'+1] = used[c[len-1]-'a'+1] = true;
indeg[c[len-1]-'a'+1]++, outdeg[c[0]-'a'+1]++;
merge(c[0]-'a'+1, c[len-1]-'a'+1);
}
ok()?puts("Ordering is possible."):puts("The door cannot be opened.");
}
return 0;
}

ac情况

Status Accepted
Time 93ms
Memory 1220kB
Length 1462
Lang G++
Submitted 2019-09-06 11:03:49
Shared
RemoteRunId 30517742

参考

【1】https://yfsyfs.github.io/2019/09/06/hdu-1878-%E6%AC%A7%E6%8B%89%E5%9B%9E%E8%B7%AF-%E5%88%A4%E6%96%AD%E6%97%A0%E5%90%91%E5%9B%BE%E6%98%AF%E5%90%A6%E5%AD%98%E5%9C%A8%E6%AC%A7%E6%8B%89%E5%9B%9E%E8%B7%AF/