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+10 int 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; }