题意:
输入n(n≤100000)个单词,是否可以把所有这些单词排成一个序列,使得每个单词的第一个字母和上一个单词的最后一个字母相同(例如acm、malform、mouse)。每个单词最
多包含1000个小写字母。输入中可以有重复单词。
分析:
可以看出, 把字母看成顶点(最多26个), 然后单词就是有向边, 单词与单词之间的关系就连接起来了, 然后建立邻接矩阵, 自环的可以忽略, 记录输入的字母有哪几个, 字母的度数。
然后图中存在欧拉通路的条件有2个
(1) 连通(我用了dfs来判断)
(2) 要么没有奇度顶点, 如果有, 那么肯定是有一个入度-出度=1 有一个入度-出度= -1。
用好这两个条件就可以判定应该就可以得出答案了
1 #include <bits/stdc++.h> 2 using namespace std; 3 int degree[26],used[26];//度数 有没有使用过 4 int G[26][26];// 邻接矩阵 5 int n; 6 int id(int a){ 7 return a-'a'; 8 } 9 int vis[26]; 10 void dfs(int u){ 11 vis[u] = 1; 12 for(int i = 0; i < 26; i++){ 13 if(G[u][i] && !vis[i]){ 14 dfs(i); 15 } 16 } 17 } 18 19 bool judge(){ 20 int num1 = 0, num2 = 0; 21 int u = 0, v; 22 for(int i = 0; i< 26; i++){ 23 if(used[i]){ 24 u = i;//u一开始等于图中任意一个顶点 25 break; 26 } 27 } 28 for(int i = 0; i < 26; i++){ 29 if(used[i]){ 30 if(degree[i] != 0){ 31 if(degree[i] == 1) {num1++; u = i;}//此时u就要等于入度>出度的顶点了 32 else if(degree[i] == -1){num2++; v = i;} 33 else return false; 34 } 35 } 36 } 37 if((num1 || num2) && num1 + num2 != 2) return false;//如果有 而且不是只有2个 就可以判为false了 38 39 memset(vis,0,sizeof(vis)); 40 dfs(u); 41 for(int i = 0; i < 26; i++){ 42 if(used[i] && !vis[i]){//如果有这个点, 遍历又没遍历到 false; 43 return false; 44 } 45 } 46 return true; 47 48 } 49 int main(){ 50 int T; 51 scanf("%d", &T); 52 while(T--){ 53 memset(degree,0,sizeof(degree)); 54 memset(used,0,sizeof(used)); 55 memset(G,0,sizeof(G)); 56 scanf("%d", &n); 57 for(int i = 0; i < n; i++){ 58 char s[1007]; 59 scanf("%s", s); 60 int s1 = s[0] , s2 = s[strlen(s)-1]; 61 if(s1 != s2){ 62 G[id(s1)][id(s2)] = 1; 63 } 64 used[s1 -'a'] = 1; 65 used[s2 -'a'] = 1; 66 degree[id(s1)]++;//出度++ 67 degree[id(s2)]--;//入度-- 68 } 69 // for(int i = 0; i<26; i++){//观察度数 70 // if(used[i]) 71 // printf("%c %d ", i+'a', degree[i]); 72 // } 73 printf("%s ", judge()? "Ordering is possible.":"The door cannot be opened."); 74 } 75 }