一道简单的dfs+贪心剪枝

单词接龙      NOIp2000

题目描述

单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合部分合为一部分,例如 beastbeast和astonishastonish,如果接成一条龙则变为beastonishbeastonish,另外相邻的两部分不能存在包含关系,例如atat 和 atideatide 间不能相连。

输入格式

输入的第一行为一个单独的整数nn (n \le 20n20)表示单词数,以下nn 行每行有一个单词,输入的最后一行为一个单个字符,表示“龙”开头的字母。你可以假定以此字母开头的“龙”一定存在.

输出格式

只需输出以此字母开头的最长的“龙”的长度

一开始觉得是个裸的dfs,结果被样例卡了一会儿,才发现需要贪心。

题目很简单,英语单词接龙,问龙的长度。

注意点:

1.每个单词可以用两次。

2.相邻两部分不存在包含关系。

3.最长长度。


忽略点:最长长度需要从单词末尾向前匹配,从前向后会导致前后都能接上的情况下接前面使总长度变短,后来发现这个问题懒得改顺序直接全匹配找最大值,果然被甩了个TLE。。。

 


代码:
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 int n,b[21],len,max1=0;
 4 string s[21];
 5 void dfs(int len,int ans) {
 6     if (len > max1)max1 = len;
 7     for (int i = 0; i < n; i++) {
 8         if (b[i]==2)continue;
 9         int flag = 0;
10             for (int k = s[ans].length()-1; k >= max(1, (int)(s[ans].length() - (s[i].length() - 1))); k--) {
11                 flag = 0;
12                 for (int j = 0,h=k; h < s[ans].length(); j++,h++) {
13                     if (s[ans][h] != s[i][j]) { flag = -1; break; }
14                 }
15                 if (flag == 0) {
16                     flag = s[ans].length()-k;
17                     break;
18                 }
19             }
20             if (flag > 0) {
21                 b[i]++;
22                 dfs(len + s[i].length() - flag, i);
23                 b[i]--;
24             }
25     }
26 }
27 int main() {
28     ios::sync_with_stdio(false);
29     cin >> n;
30     for (int i = 0; i < n; i++) {
31         cin >> s[i];
32     }
33     char c;
34     cin >> c;
35     for (int i = 0; i < n; i++) {
36         memset(b, 0, sizeof(b));
37         if (s[i][0] == c) {
38             b[i] = 1;
39             dfs(s[i].length(),i);
40             b[i] = 0;
41         }
42     }
43     cout << max1 << endl;
44     return 0;
45 }

 

posted @ 2020-05-11 00:51  Sympa  阅读(177)  评论(0)    收藏  举报