题意:给出n个单词,然后单词接龙(两个单词拼接时交界处字母要相同 ),问是否可以形成一条链。
解法:首先这是很经典的欧拉路的定义。
其中欧拉路有两种,
一种是欧拉通路,就是指形成一条链的。它满足,只有一个点的入度是1出度为0,一个点的入度为0出度是1,其他点的入度和出度都是偶数并且相等。
一种是欧拉回路,就是指可以形成一条环的。它满足,所有点的入度和出度都是偶数并且相等。
但是但是,它们都要先满足一个先天条件!那就是图必须是连通的。不能出现有两条链,两个环的情况。判断是否联通,对于这道题而言,可以用并查集来判断整个图是否连通。
代码如下:
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<utility>
#include<stack>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<set>
#include<map>
using namespace std;
int T, n, len;
int in[30];
char str[1005];
int par[30];
set <int> s;
int vst[30];
int Find(int x) {
int tmp = x;
while(x != par[x])
x = par[x];
int root = x;
x = tmp;
while(x != par[x]) {
tmp = par[x];
par[x] = root;
x = tmp;
}
return root;
}
void Union(int a, int b) {
int x = Find(a);
int y = Find(b);
if(x != y) {
par[y] = x;
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("poj_in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
scanf("%d", &T);
while(T--) {
s.clear();
memset(in, 0, sizeof(in));
memset(vst, 0, sizeof(vst));
for(int i = 0; i < 30; i++)
par[i] = i;
scanf("%d", &n);
for(int i = 0; i < n; i++) {
scanf("%s%n", str, &len);
int a = str[0] - 'a', b = str[len - 2] - 'a';
in[a]--;
in[b]++;
vst[a] = 1;
vst[b] = 1;
Union(a, b);
}
for(int i = 0; i < 26; i++) {
if(!vst[i])
continue;
int x = Find(i);
s.insert(x);
}
int cnt1 = 0, cnt2 = 0;
for(int i = 0; i < 26; i++) {
if(in[i] < 0)
cnt1 += in[i];
else
cnt2 += in[i];
}
// for(set<int>::iterator iter = s.begin(); iter != s.end(); iter++)
// printf("%d ", *iter);
// printf("\n");
if(s.size() > 1)
printf("The door cannot be opened.\n");
else if(n == 1 || (cnt1 == -1 && cnt2 == 1) || (cnt1 == 0 && cnt2 == 0))
printf("Ordering is possible.\n");
else
printf("The door cannot be opened.\n");
}
return 0;
}