我这里的姿势比较诡异,因为是直接试出来的。还是要记结论,更靠谱。
欧拉通路
【无向图】连通 + 每个顶点的度数都为偶数 或 仅有两个点的度数为偶数
【有向图】连通 + 每个顶点的入度 = 出度 或 有且仅有一个顶点的入度比出度多1同时一个顶点的出度比入度多1,其余出度等于入度
#include <iostream>
#include <queue>
#include <algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
#define MAX 30
char s[1010];
int ind[MAX];
int outd[MAX];
int degree[MAX];
int vis[MAX];
int fa[MAX];
int find(int x) {
if (x != fa[x])
fa[x] = find(fa[x]);
return fa[x];
}
void Union(int x, int y) {
int fx = find(x);
int fy = find(y);
if (fx == fy)
return;
fa[fy] = fx;
}
int main(void) {
int t, n;
scanf("%d", &t);
while (t--) {
for (int i = 0; i <= MAX; i++)
fa[i] = i;
scanf("%d", &n);
int nn = n;
memset(ind, 0, sizeof(ind));
memset(degree, 0, sizeof(degree));
memset(outd, 0, sizeof(outd));
memset(vis, 0, sizeof(vis));
while (nn--) {
scanf("%s", s);
int len = strlen(s);
int f = s[0] - 'a';
outd[f]++;
vis[f] = 1;
int e = s[len - 1] - 'a';
ind[e]++;
vis[e] = 1;
Union(f, e);
}
int ji = 0, ou = 0;
bool flag = true;
int cnt = 0;
int cnt_u = 0;
for (int i = 0; i < 26; i++) {
if (!vis[i])
continue;
if (fa[i] == i)
cnt_u++;
cnt++;
degree[i] = ind[i] + outd[i];
if (degree[i] % 2 == 0) {
ou++;
if (outd[i] != ind[i]) {
flag = false;
}
}
else
ji++;
}
//图要连通
if (cnt_u != 1)
printf("The door cannot be opened.\n");
else if (cnt == 1)
printf("Ordering is possible.\n");
//所有点都是偶数度的时候,点的入度要等于出度
else if (ji != 2) {
if (cnt == ou && flag) {
printf("Ordering is possible.\n");
}
else
printf("The door cannot be opened.\n");
}
//只存在两个奇数度的点时,除了这两个奇度点外,其他点出度等于入度
//这两个奇度点一个入度=出度+1,另一个出度=入度+1(我没有判断也ac了)
else {
if (flag)
printf("Ordering is possible.\n");
else
printf("The door cannot be opened.\n");
}
}
return 0;
}