You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

82 lines
2.7 KiB

2 years ago
#include <iostream>
#include <algorithm>
#include <queue>
#include <map>
#include <cstring>
#include <vector>
#include <stack>
#include <cstdio>
#include <set>
using namespace std;
const int N = 5005;
const int M = 1e5 + 10;
int din[N], dout[N];
int st[N]; // 判断哪些字母输入了并用于连通性的判断
int n;
vector<int> g[N];
int start; // 传入的节点
// 字符串
char s[M];
// 连通性判断
void dfs(int u) {
st[u] = 0; // u点访问过
for (int i = 0; i < g[u].size(); i++) {
int v = g[u][i];
if (st[v] == 1) dfs(v);
}
}
int check() {
int num1 = 0, num2 = 0; // 记录起点和终点的个数
// 利用dfs对st[i]=1的点进行标识为0如果下面检查到还存在st[i]==1的点说明点i不连通也就是没有半欧拉图
dfs(start);
for (int i = 0; i <= 26; i++) {
if (st[i]) return 0; // 基图不连通的是不可能存在欧拉路径的
// 基图在判断完连通性后,退出历史舞台
// 下面开始的逻辑将全是有向图的逻辑
if (abs(din[i] - dout[i]) > 1) return 0; // ① 如果有点的入度和出度差大于1不可能是半欧拉图
if (din[i] == dout[i] + 1) num1++; // ② 如果某个点的入度等于出度+1,则为终点
if (dout[i] == din[i] + 1) num2++; // ③ 如果某个点的出度等于入度+1为起点
}
// 有向图是不是半欧拉图(一笔画图),需满足:
// ①:基图是不是连通
// ②:如果所有点的入度等于出度,那么此图是半欧拉图
// ③:如果存在某些点的入度与出度不一致那么必须是一个入度比出度大1另一个入度比出度小1其它情况一票否决
return ((num1 == 1 && num2 == 1) || (num1 == 0 && num2 == 0));
}
int main() {
#ifndef ONLINE_JUDGE
freopen("POJ1386.in", "r", stdin);
#endif
int T;
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
memset(st, 0, sizeof st); // 是否遍历过
memset(g, 0, sizeof g); // 邻接矩阵存图
memset(din, 0, sizeof din); // 入度
memset(dout, 0, sizeof dout); // 出度
while (n--) {
scanf("%s", s);
int l = s[0] - 'a';
int r = s[strlen(s) - 1] - 'a';
g[l].push_back(r), g[r].push_back(l);
dout[l]++, din[r]++; // 记录出度和入度
st[l] = st[r] = 1; // 标识已出现过 
start = l; // 随意记录一个起始点
}
if (check())
printf("Ordering is possible.\n");
else
printf("The door cannot be opened.\n");
}
return 0;
}