例题6-16 单词 UVa10129

来源:互联网 发布:希拉里失败 知乎 编辑:程序博客网 时间:2024/06/05 10:56

1.题目描述:点击打开链接

2.解题思路:本题利用欧拉回路存在条件解决。可以将所有的单词看做边,26个字母看做端点,那么本题其实就是问是否存在一条路径,可以到达所有出现过的字符端点。由于本题还要求了两个单词拼在一起的条件是前一个单词的右端点和本单词的左端点一样。所以这是一个有向图。根据结论:有向图的底图(忽略边的方向后的图)必须连通;有向图中最多只能有两个端点的入度不等于出度,且必须是其中一点的入度比出度小1,另一点的入度比出度大1。因此先判断端点是否都连通,再判断每个端点的度数是否满足结论即可。

那么,如何判断连通性呢?第一种方法是利用DFS,第二种方法可以利用并查集。本题利用并查集来判断是否连通。

3.代码:

#define _CRT_SECURE_NO_WARNINGS #include<iostream>#include<algorithm>#include<string>#include<sstream>#include<set>#include<vector>#include<stack>#include<map>#include<queue>#include<deque>#include<cstdlib>#include<cstdio>#include<cstring>#include<cmath>#include<ctime>#include<functional>using namespace std;#define N 100000+10int u[N], v[N];int din[26], dout[26],vis[26];int p[N];int n;void clear(){memset(p, 0, sizeof(p));memset(vis, 0, sizeof(vis));memset(din, 0, sizeof(din));memset(dout, 0, sizeof(dout));}int find(int x){return p[x] == x ? x : p[x] = find(p[x]);}bool is_connected()//利用并查集来判断底图是否连通{for (int i = 0; i < 26; i++)p[i] = i;for (int i = 0; i < n; i++){int x = find(u[i]), y = find(v[i]);if (x != y)p[x] = y;}int i = 0;for (i; !vis[i]; i++);int x = find(i);for (int j = i + 1; j < 26;j++)if (vis[j]){int y = find(j);if (x != y)return false;}return true;}int main(){//freopen("t.txt", "r", stdin);int T;scanf("%d", &T);while (T--){clear();scanf("%d", &n);char s[1000 + 10];for (int i = 0; i < n; i++){scanf("%s", s);int len = strlen(s);u[i] = s[0] - 'a', v[i] = s[len - 1] - 'a';dout[u[i]]++, din[v[i]]++;//统计入度,出度vis[u[i]] = 1, vis[v[i]] = 1; //标记出现过的字符}int ok = 1;if (is_connected()){int cnt = 0;for (int i = 0; i < 26;i++)if (vis[i]){if (din[i] != dout[i]){if (din[i] == dout[i] - 1)cnt++;else if (din[i] == dout[i] + 1)cnt++;else{ ok = 0; break; }}if (cnt>2){ ok = 0; break; }}}else ok = 0;if (ok)puts("Ordering is possible.");else puts("The door cannot be opened.");}return 0;}

0 0
原创粉丝点击