洛谷P1127-词链

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,则doggopher可以相连成dog.gopher

另外还有一些例子:

dog.gopher

gopher.rat

rat.tiger

aloha.aloha

arachnid.dog

连接成的词可以与其他单词相连,组成更长的词链,例如:

aloha.arachnid.dog.gopher.rat.tiger

注意到,“.”两边的字母一定是相同的。

现在给你一些单词,请你找到字典序最小的词链,使得这些单词在词链中出现且仅出现一次。

 Input

第一行是一个正整数 n(1≤n≤1000),代表单词数量。

接下来共有 n行,每行是一个由 120 个小写字母组成的单词

 Output

 只有一行,表示组成字典序最小的词链,若不存在则只输出三个星号“ ∗∗∗”

 

 Sample Input

6
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 }
 
原文地址:https://www.cnblogs.com/npugen/p/9495296.html