hdu 5510 Bazinga (kmp+dfs剪枝) 2015ACM/ICPC亚洲区沈阳站-重现赛(感谢东北大学)

废话:

这道题很是花了我一番功夫。首先,我不会kmp算法,还专门学了一下这个算法。其次,即使会用kmp,但是如果暴力枚举的话,还是毫无疑问会爆掉。因此在dfs的基础上加上两次剪枝解决了这道题。

 

题意:

我没有读题,只是队友给我解释了题意,然后我根据题意写的题。

大概意思是给n个字符串,从上到下依次标记为1——n,寻找一个标记最大的串,要求这个串满足:标记比它小的串中至少有一个不是它的子串。

 

输入:

第一行输入一个整型t,表示共有t组数据。

每组数据首行一个整型n,表示有n个串。

接下来n行,每行一个字符串。

 

输出:

输出格式为”Case #x: y”,其中x为组数,y表示串的标记。

如果存在满足条件的串,则输出这个串的标记,否则输出-1

 

题解:

  1. 使用dfs,源串从标记最大的串(串n-1)开始,匹配串从比源串小的串开始,从大到小依次匹配。
  2. 如果两个串匹配,则继续匹配更小的匹配串。如果两个串不匹配,则记录不匹配的匹配串,同时比较源串和答案的大小,答案取较大值,同时执行3。如果匹配串直到匹配到标记最小的串(串0),所有串都可以和源串匹配,则执行4
  3. 源串回溯,然后用回溯的源串和记录的匹配串进行比较,即,进行2
  4. 当前源串不满足条件,回溯到dfs结束。
  5. 输出答案。

 

需要注意的有两点——

  1. 如果当前源串Aj与当前匹配串Ai不匹配,那么可知当前源串的父串Ak,即当前源串的源串,也可以直接与Ai比较,而不需要与AjAi之间的串匹配,因为Al(i < l < j) 一定是Ak的子串。这点很容易证明。
  2. 如果源串Ak一直递归到最小的串A0都匹配,那么任意串Ai(0 < i <= k) 都和A0匹配,即A0是任意串Ai的子串。那么任意Ai都不可能是答案。

 

代码如下——

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cmath>
  4 #include <algorithm>
  5 using namespace std;
  6 
  7 const int N = 2010;
  8 
  9 int Next[N];
 10 char s[510][N];
 11 int t, n;
 12 int lenS, lenT;
 13 int ans;
 14 int mid;                                                        //剪枝,放置某个串被多次访问
 15 
 16 void init()
 17 {
 18     scanf("%d", &n);
 19     for(int i = 0; i < n; i++) scanf("%s", s[i]);
 20     ans = -2;
 21     mid = -1;
 22 }
 23 
 24 void kmpNext(char* T)                                           //计算Next数组
 25 {
 26     int i = 1;
 27     Next[0] = -1;
 28     while(i < lenT)
 29     {
 30         int j = 0;
 31         while(T[j] == T[i])
 32         {
 33             Next[i] = j;
 34             i++;
 35             j++;
 36         }
 37         Next[i] = j;
 38         i++;
 39     }
 40 }
 41 
 42 bool kmp(char* S, char* T)                                      //kmp算法
 43 {
 44     lenS = strlen(S);
 45     lenT = strlen(T);
 46     kmpNext(T);
 47     int i = 0, j = 0;
 48     while(i < lenS && j < lenT)
 49     {
 50         if(j == -1)
 51         {
 52             i++;
 53             j = 0;
 54         }
 55         else if(S[i] == T[j])
 56         {
 57             i++;
 58             j++;
 59         }
 60         else j = Next[j];
 61     }
 62     if(j == lenT) return 1;
 63     return 0;
 64 }
 65 
 66 bool dfs(int x)                         //递归寻找子串
 67 {
 68     for(int i = x-1; i >= 0; i--)
 69     {
 70         if(mid != -1 && mid != i) continue;         //剪枝,如果串Ai从未查询过,或者串Ax的子串含不串Ai,那么查询Ax是否含Ai
 71         if(kmp(s[x], s[i]))
 72         {
 73             if(i == 0) return 1;
 74             mid = -1;                               //如果串Ax含串Ai,那么mid归为-1
 75             bool flag = dfs(i);
 76             if(flag) return 1;                      //剪枝,如果串A0是串Ax的子串,那么Ax不符合条件
 77         }
 78         else
 79         {
 80             ans = ans > x ? ans : x;                //永远取最大值
 81             mid = i;
 82             break;
 83         }
 84 
 85 
 86     }
 87     return 0;
 88 }
 89 
 90 void work()
 91 {
 92     dfs(n-1);
 93 }
 94 
 95 void outit(int tm)
 96 {
 97     printf("Case #%d: %d\n", tm, ans+1);
 98 }
 99 
100 int main()
101 {
102     scanf("%d", &t);
103     for(int tm = 1; tm <= t; tm++)
104     {
105         init();
106         work();
107         outit(tm);
108     }
109 }
View Code

 

Kmp算法——

http://www.cnblogs.com/mypride/p/4950245.html

 

ps. 看了看别人的代码,有些直接用了迭代法,复杂度为n^2/2,不过加上了一个感觉不太靠谱的剪枝。我算了算,最坏情况下时间好像还有可能爆掉。但是运行结果竟然不比我的慢多少,醉了。可能我算时间的方法有问题?或者数据特殊?

唉……革命尚未成功,同志仍需努力啊!

你可能感兴趣的:(hdu 5510 Bazinga (kmp+dfs剪枝) 2015ACM/ICPC亚洲区沈阳站-重现赛(感谢东北大学))