首先将单词看成是连接首字母和尾字母的有向边,然后在建立图的过程当中记录每个字母的入度和出度。当无向图建立好了之后,首先利用队列进行DFS遍历,判断图是否联通,如果图不联通则直接否定,如果图是联通的,那么逐个分析每个顶点的入度和出度只差,只有两种情况可以接收:第一种是所有顶点的出度和入度都相等,第二种情况是仅仅存在两个顶点的出度不等于入度,并且其中一个顶点的出度减去入度为1,另外一个顶点的入度减去出度为1,同时要保证出度与入度之间没有其他差值的情况存在即可,具体实现见如下源代码:
#include<iostream>
#include<vector>
#include<string>
#include<set>
#include<stack>
#include<queue>
#include<map>
#include<algorithm>
#include<cmath>
#include<iomanip>
#include<cstring>
#include<sstream>
using namespace std;
int T;
int main(){
cin >> T;
while (T--){
int in[26], out[26];
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
int N;
cin >> N;
int area[26][26];
set<char> st;
bool visit[26];
memset(visit,false,sizeof(visit));
memset(area,0,sizeof(area));
for (int i = 0; i < N; i++){
string s;
cin >> s;
st.insert(s[0]);
st.insert(s[s.size()-1]);
int index1 = s[0] - 'a';
int index2 = s[s.size() - 1] - 'a';
out[index1]++;
in[index2]++;
area[index1][index2] = 1;
area[index2][index1] = 1;
}
int start = (*st.begin()) - 'a';
queue<int> q;
q.push(start);
visit[start] = true;
int amount = 0;
while (!q.empty()){
int index = q.front();
q.pop();
amount++;
for (int i = 0; i < 26; i++){
if (area[index][i] && !visit[i]){
q.push(i);
visit[i] = true;
}
}
}
if (amount != st.size()){
cout << "The door cannot be opened." << endl;
}
else{
int first = 0;
int second = 0;
int other = 0;
for (int i = 0; i < 26; i++){
if (out[i] - in[i] == 1) first++;
else if (in[i] - out[i] == 1) second++;
else if (abs(in[i] - out[i]) != 0) other++;
}
if ((first == 1 && second == 1 && other == 0) || (first == 0 && second == 0 && other == 0))
cout << "Ordering is possible." << endl;
else cout << "The door cannot be opened." << endl;
}
}
//system("pause");
return 0;
}