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

                因为自己考虑不周全的缘故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))


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值