博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
poj 2406 && poj 1961 (KMP)
阅读量:7031 次
发布时间:2019-06-28

本文共 1828 字,大约阅读时间需要 6 分钟。

poj2406

给定一个字符串,问最多是多少个相同子串不重叠连接构成。

 

KMP的next数组应用。这里主要是如何判断是否有这样的子串,和子串的个数。

next数组的作用是在匹配无法进行下去时,可继续匹配的位置。这就要求next[j]必须为满足str[1..next[j]] = str[j-next[j]+1..j]的最大值。对于串的每一个前缀都取满足条件的最大值,则next[len]的值即为前一个子串的尾位置。

例如ababab,next[4]的值为2,即指向第一个b,因为str[1..2] = str[3..4],同理next[6]的值为4,这样就使得str[1..2] = str[3..4] = str[5..6],显然ab为满足条件的子串。

若为abababa,显然除其本身外,没有子串满足条件。而分析其next数组,next[7] = 5,next[5] = 3,next[3] = 1,即str[2..7]可由ba子串连接构成,那怎么否定这样的情况呢?很简单,若该子串满足条件,则len%sublen必为0。sunlen可由上面的分析得到为len-next[len]。

(这里可以加一个优化,长度为素数的输出为1,不过效率没见提高0 0)

因为子串是首尾相接,len/sublen即为substr的个数。

#include<cstdio>
#include<cstring>
char str[
1000001] ;
int next[
1000001] ;
int len ;
void get_next(){
//
根据已知next推出
    next[
1] = 
0 ;
    
int j = 
0 ;
    
for(
int i=
2; i<=len; i++){
        
while(j>
0&&str[j+
1]!=str[i])
            j = next[j] ;
        
if(str[j+
1]==str[i])    j ++ ;
        next[i] = j ;
    }
}
int main(){
    
while(scanf(
"
%s
", str+
1)!=EOF){
        
if(str[
1]==
'
.
'
break ;
        len = strlen(str+
1) ;
        get_next() ;
        
if(len%(len-next[len])==
0){
            printf(
"
%d\n
", len/(len-next[len])) ;
            
//
for(int i=0; i<=len; i++)
                
//
printf("%d ", next[i]) ;
            
continue ;
        }
        printf(
"
1\n
") ;
        
//
for(int i=0; i<=len; i++)
            
//
printf("%d ", next[i]) ;
    }
    
return 
0 ;

poj1961

1961与 2406只是多了枚举的一步,而且要求sublen>1。

code: 

#include<cstdio>
char str[
1000001] ;
int next[
1000001] ;
int len ;
void get_next(){
//
根据已知next推出
    next[
1] = 
0 ;
    
int j = 
0 ;
    
for(
int i=
2; i<=len; i++){
        
while(j>
0&&str[j+
1]!=str[i])
            j = next[j] ;
        
if(str[j+
1]==str[i])    j ++ ;
        next[i] = j ;
    }
}
int main(){
    
int t = 
0 ;
    
while(~scanf(
"
%d
", &len)&&len){
        scanf(
"
%s
", str+
1) ;
        t ++ ;
        get_next() ;
        printf(
"
Test case #%d\n
", t) ;
        
for(
int i=
2; i<=len; i++){
            
if(next[i]&&i%(i-next[i])==
0)
//
K>1,所以加上next[i]!=0的判断
                printf(
"
%d %d\n
", i, i/(i-next[i])) ;
        }
        printf(
"
\n
") ;
    }

转载于:https://www.cnblogs.com/xiaolongchase/archive/2012/02/04/2338595.html

你可能感兴趣的文章
httpd的简单配置(转)
查看>>
yum简介(转)
查看>>
架构漫谈(一):什么是架构?(转)
查看>>
Socket 专题
查看>>
DNS安全浅议、域名A记录(ANAME),MX记录,CNAME记录 专题
查看>>
codeforces 877E Danil and a Part-time Job
查看>>
svn服务器时间与本地时间不同步解决
查看>>
postgres10.2时区研究
查看>>
ie9以下不支持html5 解决方法
查看>>
JAVA异常体系
查看>>
C#'~'按位取反运算符的使用
查看>>
HTTP协议
查看>>
防止SQL注入
查看>>
java.io几种读写文件的方式
查看>>
jquery 点击查看,收起特效
查看>>
JS自学笔记05
查看>>
SQL Server参数化查询中应用Like
查看>>
如何用弹出窗口显示进度
查看>>
mysql优化
查看>>
自动化常识
查看>>