Problem 洛谷P1127-词链
Accept: 256 Submit: 1.3k
Time Limit: 1000 mSec Memory Limit : 128MB
Problem Description
如果单词 XXX 的末字母与单词 YYY 的首字母相同,则 XXX 与 YYY 可以相连成 X.YX.YX.Y 。(注意: XXX 、 YYY 之间是英文的句号“.”)。例如,单词dog
与单词gopher
,则dog
与gopher
可以相连成dog.gopher
。
另外还有一些例子:
dog.gopher
gopher.rat
rat.tiger
aloha.aloha
arachnid.dog
连接成的词可以与其他单词相连,组成更长的词链,例如:
aloha.arachnid.dog.gopher.rat.tiger
注意到,“.”两边的字母一定是相同的。
现在给你一些单词,请你找到字典序最小的词链,使得这些单词在词链中出现且仅出现一次。
Input
第一行是一个正整数 n(1≤n≤1000),代表单词数量。
接下来共有 n行,每行是一个由 1到 20 个小写字母组成的单词
Output
只有一行,表示组成字典序最小的词链,若不存在则只输出三个星号“ ∗∗∗”
Sample Input
6
aloha
arachnid
dog
gopher
rat
tiger
aloha
arachnid
dog
gopher
rat
tiger
Sample Output
aloha.arachnid.dog.gopher.rat.tiger
题目链接:https://www.luogu.org/problemnew/show/P1127
这个题做的很差,感觉很简单,可能还是学艺不精。
剪枝的方式还是值得一提的,这个题乍一看上去没有剪枝的思路,当把整个链和欧拉路径联系起来思路自然就出来了。
统计每个字符串首尾字母出现次数,在首位出现就++,在末位就--,如果能够连成词链,那么每个字母的统计值只能位0或1,并且如果有1只能是同时有两个,
据此可以作为充要条件判断是否有解。与此同时,一个剪枝的方式也就出来了,如果是一个+1,一个-1的情况,那么+1的那个必定时开头,避免了很多无用的搜索。
字典序的问题还是非常简单的,先按字典序sort一下,链式前向星存图,因此加边的时候倒着来就好,遇到词链就输出,退出程序。
还有一个神奇的地方,就是abc和abcb的情况,虽然abc < abcb,但是如果有一个c、b 接上去就成了abcc...、abcbb...
好像用上述算法还是有问题的,原来还听老师讲过一个类似的题,也是这种情况下有点问题,不过都能AC...
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <string> 6 #include <stack> 7 #include <algorithm> 8 using namespace std; 9 10 const int maxn = 1000+10; 11 const int maxm = maxn*maxn; 12 13 int n,tot,head[maxn]; 14 int len[maxn]; 15 bool vis[maxn]; 16 string str[maxn]; 17 18 struct Edge{ 19 int to,next; 20 Edge(int to = 0,int next = 0) : to(to),next(next) {} 21 }edge[maxm<<1]; 22 23 void AddEdge(int u,int v){ 24 edge[tot].to = v; 25 edge[tot].next = head[u]; 26 head[u] = tot++; 27 } 28 29 int top,sta[maxn<<1]; 30 31 void output(){ 32 cout << str[sta[1]]; 33 for(int i = 2;i <= n;i++){ 34 printf("."); 35 cout << str[sta[i]]; 36 } 37 cout << endl; 38 exit(0); 39 } 40 41 void dfs(int u){ 42 vis[u] = true; 43 sta[++top] = u; 44 for(int i = head[u];i != -1;i = edge[i].next){ 45 int v = edge[i].to; 46 if(!vis[v]) dfs(v); 47 } 48 if(top == n) output(); 49 vis[u] = false; 50 top--; 51 } 52 53 const int kind = 26; 54 int con[maxn]; 55 56 int main() 57 { 58 //freopen("input.txt","r",stdin); 59 cin >> n; 60 for(int i = 1;i <= n;i++){ 61 cin >> str[i]; 62 } 63 sort(str+1,str+1+n); 64 top = 0; 65 memset(head,-1,sizeof(head)); 66 memset(vis,false,sizeof(vis)); 67 memset(con,0,sizeof(con)); 68 for(int i = 1;i <= n;i++){ 69 len[i] = str[i].size(); 70 } 71 for(int i = 1;i <= n;i++){ 72 for(int j = n;j >= 1;j--){ 73 if(i!=j && str[i][len[i]-1] == str[j][0]){ 74 AddEdge(i,j); 75 } 76 } 77 } 78 for(int i = 1;i <= n;i++){ 79 con[str[i][0]-'a']++; 80 con[str[i][len[i]-1]-'a']--; 81 } 82 int head = -1,cnt = 0,_cnt = 0; 83 for(int i = 0;i < kind;i++){ 84 if(con[i] == 1){ 85 head = i; 86 cnt++; 87 } 88 else if(con[i] == -1){ 89 _cnt++; 90 } 91 } 92 if(cnt==0 && _cnt==0){ 93 for(int i = 1;i <= n;i++){ 94 dfs(i); 95 } 96 } 97 else if(cnt==1 && _cnt==1){ 98 for(int i = 1;i <= n;i++){ 99 if(str[i][0]-'a' == head) dfs(i); 100 } 101 } 102 printf("*** "); 103 return 0; 104 }