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 }
代码君

 

你可能感兴趣的:(word)