题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1116
离散数学的知识,囧,这一块没怎么学,基础很薄弱啊。
不过对于欧拉回路/通路的结论,倒是不难推出。
欧拉通路:除首尾结点外,其余结点入度等于出度,起点出度减入度等于1,终点入度减出度等于1
欧拉回路:所有结点的入度都等于出度
思路:将每一个单词的首尾字母当做结点,首尾字母间连线,判断最后形成的有向图能否形成欧拉通路/回路,用并查集。
这题直接参考了网上的。
代码:
1 | #include<stdio.h> |
2 | #include<string.h> |
3 | #define N 27 |
4 | int out[N],in[N],flag[N],p[N],father[N]; |
5 | int find( int x) |
6 | { |
7 | int r=x; |
8 | while (father[r]!=r) |
9 | r=father[r]; |
10 | return r; |
11 | } |
12 | void Union( int a, int b) |
13 | { |
14 | int fx,fy; |
15 | fx=find(a); |
16 | fy=find(b); |
17 | if (fx!=fy) |
18 | father[fx]=fy; |
19 | } |
20 | int main() |
21 | { |
22 | int i,k,cnt,a,b,ncase,n; |
23 | char s[1002]; |
24 | scanf ( "%d" ,&ncase); |
25 | while (ncase--) |
26 | { |
27 | for (i=0;i<26;i++) |
28 | father[i]=i; //初始化 |
29 | memset (in,0, sizeof (in)); |
30 | memset (out,0, sizeof (out)); |
31 | memset (flag,0, sizeof (flag)); |
32 | scanf ( "%d" ,&n); |
33 | for (i=1;i<=n;i++) |
34 | { |
35 | scanf ( "%s" ,s); |
36 | a=s[0]- 'a' ; |
37 | b=s[ strlen (s)-1]- 'a' ; |
38 | Union(a,b); |
39 | in[b]++; |
40 | out[a]++; |
41 | flag[a]=flag[b]=1; |
42 | } |
43 | cnt=0; |
44 | for (i=0;i<26;i++) |
45 | { |
46 | father[i]=find(i); |
47 | if (flag[i] && father[i]==i) |
48 | cnt++; //计算连通分支个数 |
49 | } |
50 | if (cnt>1) //不是连通图 |
51 | { |
52 | printf ( "The door cannot be opened.\n" ); |
53 | continue ; |
54 | } |
55 | k=0; |
56 | for (i=0;i<26;i++) |
57 | { |
58 | if (flag[i] && in[i]!=out[i]) |
59 | p[k++]=i; //计算入度不等于出度的结点数 |
60 | } |
61 | if (k==0) //是欧拉回路 |
62 | { |
63 | printf ( "Ordering is possible.\n" ); |
64 | continue ; |
65 | } |
66 | if (k==2 && (out[p[0]]-in[p[0]]==1 && in[p[1]]-out[p[1]]==1 |
67 | || out[p[1]]-in[p[1]]==1 && in[p[0]]-out[p[0]]==1) ) |
68 | { //是欧拉通路 |
69 | printf ( "Ordering is possible.\n" ); |
70 | continue ; |
71 | } |
72 | printf ( "The door cannot be opened.\n" ); |
73 | } |
74 | return 0; |
75 | } |