「题解」 UVa10129 Play on Words
题意:给出
n 个单词,判断能否组成环。
把每个单词想象成它的首字母向尾字母连边(有向边)。
例如:
有向图中欧拉回路的定义:
简单来说就是
- 每个节点的入度出度都相等。
- 除两个节点外,其它节点全部满足上一条件。而这两个节点满足,其中一个的入度比出度大1,另一个的出度比入度大1
这时会有一个特殊情况:
例如:
可以看下面的一组样例,
发现
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <string>
const int MAX_N = 100000 + 10;
std::string G[MAX_N];
bool vis[27];
int in[27], out[27], fa[27];
inline void Init() {
memset(in, 0, sizeof(in));
memset(out, 0, sizeof(out));
memset(vis, false, sizeof(vis));
for (int i = 1; i <= 26; i++) fa[i] = i;
}
int find(int x) {
if (x == fa[x]) return x;
return fa[x] = find(fa[x]);
}
int main() {
std::ios::sync_with_stdio(false);
int T; std::cin >> T;
while (T--) {
int n; std::cin >> n;
Init();
for (int i = 1; i <= n; i++) {
std::cin >> G[i];
in[G[i].back() - 'a' + 1]++;
out[G[i].front() - 'a' + 1]++;
vis[G[i].back() - 'a' + 1] = vis[G[i].front() - 'a' + 1] = true;
int fx = find(G[i].back() - 'a' + 1), fy = find(G[i].front() - 'a' + 1);
if (fx != fy) {
fa[fx] = fy;
}
}
int cnt = 0;
for (int i = 1; i <= 26; i++) {
if (vis[i] && find(i) == i) ++cnt;
}
if (cnt > 1) { // 不连通
puts("The door cannot be opened.");
continue;
}
std::vector<int> odd;
for (int i = 1; i <= 26; i++) {
if (vis[i] && in[i] != out[i]) odd.push_back(i);
}
if (odd.size() != 0 && odd.size() != 2) { // 奇点个数不为0个或2个
puts("The door cannot be opened.");
continue;
}
if (odd.empty()) { //全为偶点
puts("Ordering is possible.");
continue;
}
if (in[odd.front()] - out[odd.front()] == 1 && out[odd.back()] - in[odd.back()] == 1) {
puts("Ordering is possible.");
continue;
}
if (out[odd.front()] - in[odd.front()] == 1 && in[odd.back()] - out[odd.back()] == 1) {
puts("Ordering is possible.");
continue;
}
puts("The door cannot be opened.");
}
return 0;
}