传送门!!!!!!!!----->点击打开题目链接
题意:输入一个n代表有n个单词,接下来输入n个单词,问是否可以把所有的单词排成一个序列,使得每个单词的第一个字母和上一个单词的最后一个字母相同。
思路:把字母看成节点,单词看成有向边,建图。当且仅当途中存在欧拉路径时题目叙述成立。
欧拉回路:能否从无向图中的一个节点出发走出一条道路,每条边恰好经过一次,。如果可以,则这样的路线称为欧拉道路。
欧拉道路的定理:最多只能有两个点的度入度和出度不相等,而且必须是其中一个点的出度比入度大1(把他作为起点),另一个的入度比出度大一(作为终点)。并且图是连通的。
所以这道题的思路就是判定建出来的图是否存在欧拉回路。所以需要证明两步,第一步是证明这个图是连通的,第二部是证明最多存在两个点入度和出度的不相等,且一个出度比入度大一,一个入度比出度大一。
详情看代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 30;
int vis[maxn]; //标记数组,用来标记该点是否联通。
int son,far;
int in[maxn]; // 统计某个点的入度
int out[maxn]; //统计某个点的出度
int [maxn][maxn]; // 图
void dfs(int u){ // 判断是否为连通图
vis[u] = 1;
for(int i = 0 ; i < maxn ; i ++){
if(G[u][i] && !vis[i])
dfs(i);
}
}
int main(){
string str;
int kase;
cin >> kase ;
while(kase --){
int n ,cnt = 0,n_in = 0,n_out = 0, start= 0;
cin >> n;
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
memset(G,0,sizeof(G));
memset(vis,0,sizeof(vis));
for(int i = 0 ; i < n ; i ++){ // 建图
cin >> str;
far = str[0] - 'a';
son = str[str.size() - 1] - 'a' ;
out[far] ++;
in[son] ++;
G[far][son] = 1;
}
for(int i = 0 ; i < 27 ; i++){ // 统计点的入度和出度
if(in[i] != out[i]){ //当入度和出度不相等时
if(in[i] == out[i] + 1)
n_in ++;
else if(in[i] + 1 == out[i])
n_out ++,start = i ;
else n_in += maxn;
}
if(start = 0 && in[i] == out[i]) // 当所有点入度和出度 都相等的时候,任何一个点都可以作为起点。
start = i;
}
int ok = 0;
if((n_in == 1 && n_out == 1) || (n_in == 0 && n_out ==0)){ //判断条件2是否成立
dfs(start);
ok = 1;
}
for(int i = 0 ; i < 27 ; i++) //判断条件1是否成立 当这点存在但是不连通时 cnt++;
if(vis[i] == 0 && (in[i]||out[i]))
cnt ++;
if(cnt == 0 &&ok == 1)
cout <<"Ordering is possible." <<endl;
else
cout << "The door cannot be opened." <<endl;
}
return 0;
}