题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=99
题目分析:
其实上这道题把给的单词转化成一个图,然后考察这个图是否具有一个欧拉回路。
一个图具有欧拉回路的充要条件是这个图是连通的,并且只有0或2个奇点。出度比入度大一的作为起点,出度比入度小一的作为终点。
一开始我把题目抽象错了,试图去把每个单词看成一个节点,然后抽象成图,这种做法是不对的,然而这种不对的想法纠结了我很久,以致于我一直坚持WA的提交。伤心啊。正确的应该是把字符抽象出来,单独的一个字符作为一个节点,来考虑出度和入度。如果一个字符出现在字符串首,那它的出度就+1,该字符通过这个字符串可以到达字符串尾的那个字符;如果出现在字符串尾,入度加1,字符串首的字符可通过该字符串达到该字符。想了好久才想明白。
为什么要用递归,这样节省空间,并且这里的话,递归的效率挺好的。
#include<stdio.h> #include<string.h> #include<stdlib.h> char str[1000][31]; bool used[1000]; int In[26]; int Out[26]; int s[1000];//在Judge中用来存放每个字符串的大小Size int stack[1000]; int n; int compare(const void *a, const void *b) { char *p1 = (char *)a; char *p2 = (char *)b; return strcmp(p1, p2); } int Judge() { int i; int last = -1; int first = -1; for(i = 0; i < 26; ++i) { if(In[i] != Out[i]) { //Out为在串首出现的次数,In为串尾出现的次数 if(Out[i] - In[i] == 1 && first == -1) first = i; else if(Out[i] - In[i] == -1 && last == -1) last = i; else return -1; } } if(first > -1 && last > -1) return first; else if(first == -1 && last == -1) { for(i = 0; i < 26; ++i) if(In[i] != 0) return i; } else return -1; } bool DFS(char first, int Index)//有可能有多个连通区域 { if(Index == n) return true; int i; int b,e,m; b = 0; e = n - 1; while(b <= e)//二分法查找这个首字符,排序好的,肯定快啊。速度绝对比别人快2倍 { m = (b + e)/2; if(str[m][0] == first) break; else if(str[m][0] > first) e = m - 1; else b = m + 1; } if(b > e) return false; //找到这个字符第一次出现的字符串 while(str[m][0] == first && m >= 0) --m; for(i = m + 1; str[i][0] == first; ++i) { if(!used[i]) { stack[Index] = i; used[i] = true; if(DFS(str[i][s[i] - 1], Index + 1)) return true; used[i] = false; } } return false; } int main() { int t; int i,first; scanf("%d", &t); while(t--) { scanf("%d", &n); for(i = 0; i < n; ++i) scanf("%s", str[i]); memset(used, 0, sizeof(used)); memset(In, 0, sizeof(In)); memset(Out, 0, sizeof(Out)); qsort(str, n, 31 * sizeof(char), compare); for(i = 0; i < n; ++i) { s[i] = strlen(str[i]); ++Out[str[i][0] - 'a']; ++In[str[i][s[i] - 1] - 'a']; } first = Judge(); if(first != -1 && DFS(first + 'a', 0)) { for(i = 0; i < n - 1; ++i) printf("%s.", str[stack[i]]); printf("%s\n", str[stack[n - 1]]); } else printf("***\n"); } }