zoukankan      html  css  js  c++  java
  • 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
    ", 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,不过加上了一个感觉不太靠谱的剪枝。我算了算,最坏情况下时间好像还有可能爆掉。但是运行结果竟然不比我的慢多少,醉了。可能我算时间的方法有问题?或者数据特殊?

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

  • 相关阅读:
    火狐下,td 的 bug;
    在centos6.3用yum安装redis
    Linux系统下修改环境变量PATH路径的三种方法
    网络文件常常提到类似"./run.sh"的数据,这个命令的意义是什么?
    DataGridView的自定义列排序
    【Linux】linux常用基本命令
    用户名 不在 sudoers文件中,此事将被报告。(转)
    将XML文件中的内容转换为Json对象
    C# 加载xml文档文件及加载xml字符串
    增加不存在的列
  • 原文地址:https://www.cnblogs.com/mypride/p/4951645.html
Copyright © 2011-2022 走看看