hdu 5510 Bazinga (kmp+dfs剪枝) 2015ACM/ICPC亚洲区沈阳站-重现赛(感谢东北大学)
2015-11-09 23:38
471 查看
废话:
这道题很是花了我一番功夫。首先,我不会kmp算法,还专门学了一下这个算法。其次,即使会用kmp,但是如果暴力枚举的话,还是毫无疑问会爆掉。因此在dfs的基础上加上两次剪枝解决了这道题。
题意:
我没有读题,只是队友给我解释了题意,然后我根据题意写的题。
大概意思是给n个字符串,从上到下依次标记为1——n,寻找一个标记最大的串,要求这个串满足:标记比它小的串中至少有一个不是它的子串。
输入:
第一行输入一个整型t,表示共有t组数据。
每组数据首行一个整型n,表示有n个串。
接下来n行,每行一个字符串。
输出:
输出格式为”Case #x: y”,其中x为组数,y表示串的标记。
如果存在满足条件的串,则输出这个串的标记,否则输出-1。
题解:
使用dfs,源串从标记最大的串(串n-1)开始,匹配串从比源串小的串开始,从大到小依次匹配。
如果两个串匹配,则继续匹配更小的匹配串。如果两个串不匹配,则记录不匹配的匹配串,同时比较源串和答案的大小,答案取较大值,同时执行3。如果匹配串直到匹配到标记最小的串(串0),所有串都可以和源串匹配,则执行4。
源串回溯,然后用回溯的源串和记录的匹配串进行比较,即,进行2。
当前源串不满足条件,回溯到dfs结束。
输出答案。
需要注意的有两点——
如果当前源串Aj与当前匹配串Ai不匹配,那么可知当前源串的父串Ak,即当前源串的源串,也可以直接与Ai比较,而不需要与Aj和Ai之间的串匹配,因为Al(i < l < j) 一定是Ak的子串。这点很容易证明。
如果源串Ak一直递归到最小的串A0都匹配,那么任意串Ai(0 < i <= k) 都和A0匹配,即A0是任意串Ai的子串。那么任意Ai都不可能是答案。
代码如下——
View Code
Kmp算法——
/article/5857187.html
ps. 看了看别人的代码,有些直接用了迭代法,复杂度为n^2/2,不过加上了一个感觉不太靠谱的剪枝。我算了算,最坏情况下时间好像还有可能爆掉。但是运行结果竟然不比我的慢多少,醉了。可能我算时间的方法有问题?或者数据特殊?
唉……革命尚未成功,同志仍需努力啊!
这道题很是花了我一番功夫。首先,我不会kmp算法,还专门学了一下这个算法。其次,即使会用kmp,但是如果暴力枚举的话,还是毫无疑问会爆掉。因此在dfs的基础上加上两次剪枝解决了这道题。
题意:
我没有读题,只是队友给我解释了题意,然后我根据题意写的题。
大概意思是给n个字符串,从上到下依次标记为1——n,寻找一个标记最大的串,要求这个串满足:标记比它小的串中至少有一个不是它的子串。
输入:
第一行输入一个整型t,表示共有t组数据。
每组数据首行一个整型n,表示有n个串。
接下来n行,每行一个字符串。
输出:
输出格式为”Case #x: y”,其中x为组数,y表示串的标记。
如果存在满足条件的串,则输出这个串的标记,否则输出-1。
题解:
使用dfs,源串从标记最大的串(串n-1)开始,匹配串从比源串小的串开始,从大到小依次匹配。
如果两个串匹配,则继续匹配更小的匹配串。如果两个串不匹配,则记录不匹配的匹配串,同时比较源串和答案的大小,答案取较大值,同时执行3。如果匹配串直到匹配到标记最小的串(串0),所有串都可以和源串匹配,则执行4。
源串回溯,然后用回溯的源串和记录的匹配串进行比较,即,进行2。
当前源串不满足条件,回溯到dfs结束。
输出答案。
需要注意的有两点——
如果当前源串Aj与当前匹配串Ai不匹配,那么可知当前源串的父串Ak,即当前源串的源串,也可以直接与Ai比较,而不需要与Aj和Ai之间的串匹配,因为Al(i < l < j) 一定是Ak的子串。这点很容易证明。
如果源串Ak一直递归到最小的串A0都匹配,那么任意串Ai(0 < i <= k) 都和A0匹配,即A0是任意串Ai的子串。那么任意Ai都不可能是答案。
代码如下——
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; const int N = 2010; int Next ; char s[510] ; int t, n; int lenS, lenT; int ans; int mid; //剪枝,放置某个串被多次访问 void init() { scanf("%d", &n); for(int i = 0; i < n; i++) scanf("%s", s[i]); ans = -2; mid = -1; } void kmpNext(char* T) //计算Next数组 { int i = 1; Next[0] = -1; while(i < lenT) { int j = 0; while(T[j] == T[i]) { Next[i] = j; i++; j++; } Next[i] = j; i++; } } bool kmp(char* S, char* T) //kmp算法 { lenS = strlen(S); lenT = strlen(T); kmpNext(T); int i = 0, j = 0; while(i < lenS && j < lenT) { if(j == -1) { i++; j = 0; } else if(S[i] == T[j]) { i++; j++; } else j = Next[j]; } if(j == lenT) return 1; return 0; } bool dfs(int x) //递归寻找子串 { for(int i = x-1; i >= 0; i--) { if(mid != -1 && mid != i) continue; //剪枝,如果串Ai从未查询过,或者串Ax的子串含不串Ai,那么查询Ax是否含Ai if(kmp(s[x], s[i])) { if(i == 0) return 1; mid = -1; //如果串Ax含串Ai,那么mid归为-1 bool flag = dfs(i); if(flag) return 1; //剪枝,如果串A0是串Ax的子串,那么Ax不符合条件 } else { ans = ans > x ? ans : x; //永远取最大值 mid = i; break; } } return 0; } void work() { dfs(n-1); } void outit(int tm) { printf("Case #%d: %d\n", tm, ans+1); } int main() { scanf("%d", &t); for(int tm = 1; tm <= t; tm++) { init(); work(); outit(tm); } }
View Code
Kmp算法——
/article/5857187.html
ps. 看了看别人的代码,有些直接用了迭代法,复杂度为n^2/2,不过加上了一个感觉不太靠谱的剪枝。我算了算,最坏情况下时间好像还有可能爆掉。但是运行结果竟然不比我的慢多少,醉了。可能我算时间的方法有问题?或者数据特殊?
唉……革命尚未成功,同志仍需努力啊!
相关文章推荐
- 关于数据结构三种简单的排序总结
- PM 周刊第 4 期 2015-11-09
- 动手动脑
- 《C陷阱与缺陷》之1词法"陷阱"
- tomcat服务器配置及使用
- hadoop2.7文档翻译第二天
- leetcode-Lowest Common Ancestor of a Binary Search Tree
- lua开发之--mysql和http模块
- ShortestPath:Layout(POJ 3169)(差分约束的应用)
- 转载linq to sql 的详解
- CC150 Reading Notes 2: Linked Lists
- Spark修炼之道(高级篇)——Spark源码阅读:第十节 Standalone运行模式解析
- loadView与viewDidLoad不同
- Java记录 -74- 自定义泛型
- 对象包装器与自动(拆箱)装箱+参数数量可变的方法+枚举类
- APNS详解
- KD树——UCI数据集IRIS
- 如何用Java调用R(包含在服务器安装的过程)以及用R生成的图片如何用<img>标签访问
- 深入理解计算机系统(CSAPP)实验二 datalab-handout
- C++ - 异常处理:try,catch,throw,finally的用法