单词拼接
时间限制:3000 ms | 内存限制:65535 KB
难度:5
-
描述
-
给你一些单词,请你判断能否把它们首尾串起来串成一串。
前一个单词的结尾应该与下一个单词的道字母相同。
如
aloha
dog
arachnid
gopher
tiger
rat
可以拼接成:aloha.arachnid.dog.gopher.rat.tiger
-
输入
- 第一行是一个整数N(0<N<20),表示测试数据的组数
每组测试数据的第一行是一个整数M,表示该组测试数据中有M(2<M<1000)个互不相同的单词,随后的M行,每行是一个长度不超过30的单词,单词全部由小写字母组成。
输出 - 如果存在拼接方案,请输出所有拼接方案中字典序最小的方案。(两个单词之间输出一个英文句号".")
如果不存在拼接方案,则输出
***
样例输入 -
2 6 aloha arachnid dog gopher rat tiger 3 oak maple elm
样例输出 -
aloha.arachnid.dog.gopher.rat.tiger ***
如果满足题意,那么数据一定可以构成欧拉回路,欧拉回路的条件是: 所有点的入度和出度相等;欧拉路径的条件是:满足欧拉回路条件或者图中最多有一个点入度比出度大1,至多有一个点出度比入度大一,如果满足以上条件,再进行dfs深搜找出一条路径,然后输出,如果找不到则不存在
实上这道题把给的单词转化成一个图,然后考察这个图是否具有一个欧拉回路。 - 第一行是一个整数N(0<N<20),表示测试数据的组数
-
#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"); } }
一个图具有欧拉回路的充要条件是这个图是连通的,并且只有0或2个奇点。出度比入度大一的作为起点,出度比入度小一的作为终点。
把字符抽象出来,单独的一个字符作为一个节点,来考虑出度和入度。如果一个字符出现在字符串首,那它的出度就+1,该字符通过这个字符串可以到达字符串尾的那个字符;如果出现在字符串尾,入度加1,字符串首的字符可通过该字符串达到该字符。
要用递归,这样节省空间,并且这里的话,递归的效率挺好的。