UVA10129———欧拉道路

题目

输入n(n≤100000)个单词,是否可以把所有这些单词排成一个序列,使得每个单词的第一个字母和上一个单词的最后一个字母相同(例如 acm,malform,mouse)。每个单词最多包含1000个小写字母。输入中可以有重复单词。

解题思路

把字母看作结点,单词看作有向边,则问题有解等价于图中存在欧拉道路。有向图中存在欧拉道路的条件有两个:一是底图(忽略边的方向后得到的无向图)连通,二是度数满足不存在奇点或奇点数为2。度数判读只要在输入时记录每个顶点的入度出度,而连通性判断有两种:DFS和并查集。

代码实现

dfs判断连通性+特判入出度

 1 #include<stdio.h>
 2 #include<cstring>
 3 using namespace std;
 4 
 5 const int maxn = 26 + 5;
 6 int G[maxn][maxn],in[maxn],out[maxn];
 7 int vis[maxn];        //点是否访问,不是边
 8 int n;
 9 char word[1000 + 10];
10 
11 void dfs(int u)
12 {
13     vis[u] = 1;
14     for (int v = 0; v < maxn; v++)  if (G[u][v])
15     {
16         G[u][v] = G[v][u] = 0;
17         //G[u][v]--; G[v][u]--;
18         dfs(v);
19     }
20 }
21 
22 int main()
23 {
24     int T;
25     scanf("%d", &T);
26     while (T--)
27     {
28         memset(G, 0, sizeof(G));
29         memset(in, 0, sizeof(in));
30         memset(out, 0, sizeof(out));
31         memset(vis, 0, sizeof(vis));
32         scanf("%d", &n);
33         int start;            //起点
34         while (n--)
35         {
36             scanf("%s", word);
37             int len = strlen(word);
38             int u = word[0] - 'a', v = word[len - 1] - 'a';
39             start = u;
40             vis[u] = vis[v] = -1;    //出现过的标为-1
41             G[u][v] = G[v][u] = 1;    //连通性按无向图处理
42             //G[u][v]++; G[v][u]++;
43             out[u]++;        //度数按有向图处理
44             in[v]++;
45         }
46 
47         bool flag = true;    //满足要求为true
48         int s_odd = 0,t_odd = 0;    //起始奇点、结束奇点
49         for (int i = 0; i < maxn; i++)
50         {
51             if (in[i] == out[i])  continue;
52             if (out[i] == in[i] + 1 && !s_odd) { start = i; s_odd = 1; }
53             else if (in[i] == out[i] + 1 && !t_odd)  t_odd = 1;
54             else { flag = false; break; }
55         }
56         if (flag)
57         {
58             dfs(start);    //也可以不从奇点出发,这个只是判断连通性
59             for (int i = 0; i < maxn; i++)
60                 if (vis[i] == -1) { flag = false; break; }
61         }
62 
63         if (flag)  printf("Ordering is possible.
");
64         else  printf("The door cannot be opened.
");
65     }
66     return 0;
67 }

并查集判断连通性+特判入出度

 1 #include<stdio.h>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<string>
 6 #include<cmath>
 7 using namespace std;
 8 
 9 const int maxn = 26 + 5;
10 int in[maxn], out[maxn], flag[maxn], p[maxn], fa[maxn];
11 int n;
12 
13 void init()
14 {
15     for (int i = 0; i < 26; i++)
16         fa[i] = i;
17     memset(in, 0, sizeof(in));
18     memset(out, 0, sizeof(out));
19     memset(flag, 0, sizeof(flag));
20     memset(p, 0, sizeof(p));
21 }
22 int find(int x)
23 {
24     if (fa[x] != x)    return fa[x] = find(fa[x]);
25     return fa[x];
26 }
27 
28 void unite(int x, int y)
29 {
30     int rx = find(x);
31     int ry = find(y);
32     fa[rx] = ry;
33 }
34 
35 int main()
36 {
37     int T;
38     int a, b;
39     string str;
40     scanf("%d", &T);
41     while (T--)
42 {
43         init();
44         scanf("%d", &n);
45         for (int i = 0; i < n; i++)
46         {
47             cin >> str;
48             a = str[0] - 'a';
49             b = str[str.size() - 1] - 'a';
50             unite(a, b);
51             in[a]++;
52             out[b]++;
53             flag[a] = flag[b] = 1;
54         }
55 
56         int cnt = 0;    //记录连通分量
57         int root;
58         for (int i = 0; i < 26; i++)
59         {
60             if (flag[i])
61             {
62                 root = find(i);
63                 break;
64             }
65         }
66 for (int i = 0; i < 26; i++)
67         {
68             if (flag[i])
69                 if (root != find(i)) cnt = 1;
70         }
71 
72         if (cnt) {
73             printf("The door cannot be opened.
");
74             continue;
75         }
76 
77         int k = 0; //p[i]记录度数不等的
78         for (int i = 0; i < 26; i++)
79         {
80             if (flag[i] && in[i] != out[i])  p[k++] = i;
81         }
82         if (k == 0)
83         {
84             printf("Ordering is possible.
");
85             continue;
86         }
87         if (k == 2 && (in[p[0]] - out[p[0]] == 1 && in[p[1]] - out[p[1]] == -1) || (in[p[0]] - out[p[0]] == -1 && in[p[1]] - out[p[1]] == 1))
88         {
89             printf("Ordering is possible.
");
90         continue;
91         }
92         else
93         {
94             printf("The door cannot be opened.
");
95         }
96     }
97     return 0;
98 }

 参考链接:https://blog.csdn.net/qq_29169749/article/details/51111377

原文地址:https://www.cnblogs.com/lfri/p/9922028.html