Play on Words
题目链接: http://acm.bnu.edu.cn/bnuoj/problem_show.php?pid=18547
题目大意:
有N个单词(均为小写) (N最大为100000),现在要将它们按照一定的规律排成一行,为能否实现?
规律是:前一个单词的最后一个字母必须是后一个单词的首字母,类似于单词接龙
解题思路:
这道题其实是一个欧拉道路问题,每个单词的首字母和尾字母相当于图中的顶点,并且有从首字母到尾字母的一条有向边。
欧拉道路:
一次这道题就是一个欧拉道路,欧拉道路满足的条件是除了起点和终点外,所有点的出度和入度相同,而起点的出度比入度大1,终点的入度比出度大1。
这道题还有个关键是要判断图是否连通,可以用并查集或者DFS搜索来实现。
并查集+欧拉道路:
//有向图欧拉回路 + 并查集判连通性 #include<iostream> #include<fstream> #include<cstdio> #include<cstring> #include<cmath> #include<map> #include<queue> #include<stack> #include<vector> #include<set> #include<ctype.h> #include<algorithm> #include<string> #define PI acos(-1.0) #define maxn 1000 #define INF 1<<25 #define mem(a, b) memset(a, b, sizeof(a)) typedef long long ll; using namespace std; int f[30]; int find(int x) { if (f[x] != x) f[x] = find(f[x]); return f[x]; } int main () { int i, j, t, n; cin>>t; while(t--) { bool has[30] = {false}; int sum = 0, a[30] = {0}; char str[1010]; for (i = 0; i < 26; i++) f[i] = i; cin>>n; getchar(); while(n--) { gets(str); int u = str[0] - ‘a‘, v = str[strlen(str) - 1] - ‘a‘; a[u]--; if (!has[u]) has[u] = true; a[v]++; if (!has[v]) has[v] = true; f[find(u)] = find(v); } int no = 0, out = 0, in = 0; for (i = 0; i < 26; i++) if (a[i]) { no++; if (a[i] == 1) in++; if (a[i] == -1) out++; } for (i = 0; i < 26; i++) if (has[i] && f[i] == i) sum++; if (sum == 1 && (no == 0 || (no == 2 && out == 1 && in == 1))) puts("Ordering is possible."); else puts("The door cannot be opened."); } return 0; }
DFS+欧拉道路:
//有向图欧拉回路 + bfs判连通性
bfs要从有出度的点开始搜!
//有向图欧拉回路 + bfs判连通性 #include<iostream> #include<fstream> #include<cstdio> #include<cstring> #include<cmath> #include<map> #include<queue> #include<stack> #include<vector> #include<set> #include<ctype.h> #include<algorithm> #include<string> #define PI acos(-1.0) #define maxn 1000 #define INF 1<<25 #define mem(a, b) memset(a, b, sizeof(a)) typedef long long ll; using namespace std; int mp[30][30]; int bfs(int x) // 必须是对有出度的字母进行bfs! { int vis[30] = {0}, font = 0, rear = 1, sum = 1; int que[1000] = {0}; que[font] = x; vis[x] = 1; int u, next; while(font < rear) { u = que[font++]; for (int v = 0; v < 26; v++) if (mp[u][v] && !vis[v]) { vis[v] = 1; sum++; que[rear++] = v; } } return sum; } int main () { int i, j, t, n; cin>>t; while(t--) { bool has[30] = {false}; int sum = 0, a[30] = {0}, k; char str[1010]; mem(mp, 0); cin>>n; getchar(); while(n--) { gets(str); int u = str[0] - ‘a‘, v = str[strlen(str) - 1] - ‘a‘; a[u]--; if (!has[u]) has[u] = true, sum++; a[v]++; if (!has[v]) has[v] = true, sum++; mp[u][v] = mp[v][u] = 1; k = u; } int no = 0, out = 0, in = 0; for (i = 0; i < 26; i++) if (a[i]) { no++; if (a[i] == 1) in++; if (a[i] == -1) out++; } if (sum == bfs(k) && (no == 0 || (no == 2 && out == 1 && in == 1))) puts("Ordering is possible."); else puts("The door cannot be opened."); } return 0; }