UVa 10129 (并查集 + 欧拉路径) Play on Words

题意:

有n个由小写字母的单词,要求判断是否存在某种排列使得相邻的两个单词,前一个单词末字母与后一个单词首字母相同。

分析:

将单词的两个字母看做节点,则一个单词可以看做一条有向边。那么题中所求的排列就等价于该有向图中是否存在欧拉路径。

在判断之前,首先要确定这个图是连通的,代码中用并查集来实现。

回顾一下存在欧拉路径的条件,全都是偶点或者有且仅有两个奇点。我们用deg来记录每个点的度,出度为1,入度为-1。

程序中判断存在欧拉路径的条件就是:deg全为0 或者 有两个不为0的,其中一个为1一个为-1

used记录某个字母是否出现过。

 

 1 //#define LOCAL
 2 #include <vector>
 3 #include <cstdio>
 4 #include <cstring>
 5 using namespace std;
 6 
 7 const int maxn = 1000 + 10;
 8 char word[maxn];
 9 int pa[256], deg[256], cc, used[256];
10 
11 int find(int a)
12 { return pa[a] == a ? a : pa[a] = find(pa[a]); }
13 
14 int main(void)
15 {
16     #ifdef LOCAL
17         freopen("10129in.txt", "r", stdin);
18     #endif
19 
20     int T, n;
21     scanf("%d", &T);
22     while(T--)
23     {
24         memset(used, 0, sizeof(used));
25         memset(deg, 0, sizeof(deg));
26         for(int i = 'a'; i <= 'z'; ++i)
27             pa[i] = i;
28         cc = 26;    //Á¬Í¨¿éµÄÊýÁ¿ 
29 
30         scanf("%d", &n);
31         for(int i = 0; i < n; ++i)
32         {
33             scanf("%s", word);
34             char c1 = word[0];
35             char c2 = word[strlen(word) - 1];
36             used[c1] = used[c2] = 1;
37             deg[c1]++;    deg[c2]--;
38             int p1 = find(c1);
39             int p2 = find(c2);
40             if(p1 != p2)
41             {
42                 cc--;
43                 pa[p1] = p2;
44             }
45         }
46 
47         vector<int> d;
48         for(int i = 'a'; i <= 'z'; ++i)
49         {
50             if(!used[i]) --cc;
51             else if(deg[i])    d.push_back(i);
52         }
53         bool ok = false;
54         if(cc == 1 && (d.empty() || (d.size() == 2 && (deg[d[0]] == 1 || deg[d[0]] == -1)))) ok = true;
55         if(ok)    puts("Ordering is possible.");
56         else puts("The door cannot be opened.");
57     }
58 
59     return 0;
60 }
代码君

 

posted @ 2014-09-24 20:42  AOQNRMGYXLMV  阅读(287)  评论(0编辑  收藏  举报