您的位置:首页 > 其它

100道动态规划——7 UVA 1630 folding 因为自己考虑的不周全WA了好几发。。。递推,KMP求子串周期

2016-11-03 11:41 369 查看
                因为自己考虑不周全的缘故WA了好十几发。。后来找到一个好测试数据才弄出来。。特别感谢http://blog.csdn.net/getupdown/article/details/49542145 提供的测试数据

首先是子串求周期的问题,第一反应用KMP来解决,然后KMP也调试了一会儿。。

然后就是写递推,最后通过一个print函数来重构解。

恩,状态转移方程是很好想到的,但是有细节需要注意。

设dp[i][j]表示从i~j的子串的最小长度(下标从1开始)

  那么dp[i][j]有两种转移方式,第一种是自己本身就是周期串

也需要判断一下,看能不能折叠,假如周期串+数字的长度+括号的长度比本身还要长的话,那就不用折叠了

假若可以折叠的话,那么此时的长度就是2(括号)+getbit(length/(length-next[i]j])(这是数字的长度)+dp[i][i+length-next[i][j]+1](特别注意!虽然是+一个周期的长度,但是不能直接+length-next[i][j],而是应该+dp[i][i+length-next[i][j]+1],表示+上这个周期串的最小长度,因为周期串本身可以折叠的缘故,我就是在这里WA了10发左右,自己默认+上了一个周期串的原长)

第二种就是由两个子串拼接而成

dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j])对于所有的i<=k<j来说

最后的print反着打印一遍就好了,我相信假若做了UVA 2541 Brackets Sequence的话,这个重构解应该不是难事。

getNext表示把KMP的next数组求出来,print(int i,int length)表示打印下标为i,长度为length的子串,getbit拿到一个数字的长度。

#include <cstdio>
#include <algorithm>
#include <cstring>

using std::min;

char str[110];
inline int getbit(int x){
if(x>=100)
return 3;
else if(x>=10)
return 2;
else
return 1;
}

int len,dp[105][105],next[105][105];
void getNext(),print(int i,int length);

int main(){
for(int i=1;i<=100;++i)
next[i][i-1]=-1;

while(scanf("%s",str+1)!=EOF){
len=strlen(str+1);
for(int i=1;i<=len;++i)
dp[i][i]=1;
getNext();
for(int length=2,i=1;length<=len;++length,i=1)
for(int j=length;j<=len;++j,++i){

if((length)%(length-next[i][j])==0&&length>=2+getbit((length)/(length-next[i][j]))+length-next[i][j])
dp[i][j]=2+getbit((length)/(length-next[i][j]))+dp[i][i+length-next[i][j]-1];
else
dp[i][j]=length;

for(int k=i;k<j;++k)
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]);
}

print(1,len);
printf("\n");
memset(dp,0,sizeof dp);
}
return 0;
}

void getNext(){
for(int i=1;i<=len;++i)
for(int j=i,p=next[i][j-1];j<=len;p=next[i][++j-1]){
while(p>=0&&str[j]!=str[i+p])p=next[i][i+p-1];
next[i][j]=p+1;
}
}

void print(int i,int length){
if(length==1){
printf("%c",str[i]);
return;
}
int j=i+length-1;
if(length%(length-next[i][j])==0&&length>=2+getbit(length/(length-next[i][j]))+length-next[i][j]&&dp[i][j]==2+getbit((length)/(length-next[i][j]))+dp[i][i+length-next[i][j]-1]){
printf("%d(",length/(length-next[i][j]));
print(i,length-next[i][j]);
printf(")");
return;
}
for(int k=i;k<j;++k)
if(dp[i][j]==dp[i][k]+dp[k+1][j]){

print(i,k-i+1);
print(k+1,j-k);
return;
}
}

顺便说一下那一组数据:

NEEEEEEEEEEEEERYESYESYESYESEEEEEERYESYESYESYES

答案是:
N7(E)2(6(E)R4(YES))
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐