uva 11584 划分成回文串

P3625  划分成回文串
时间限制 : 10000 MS   空间限制 : 65536 KB
问题描述


给一个字符串, 要求把它分割成若干个子串,使得每个子串都是回文串。问最少可以分割成多少个。 
例如: 
“racecar”本身就是回文串,答案为1 
“fastcar”,答案为7,分成的7个回文串为"f", "a", "s", "t", "c", "a", "r" 
“aaadbccb”,答案为3,分成的3个回文串为"aaa", "d", "bccb"


输入格式


一行,一个由小写字母构成的字符串,该字符串的长度不超过300


输出格式


一行,一个整数,表示最少分割出的回文串的个数。


样例输入

样例输入1:
racecar

样例输入2:
fastcar

样例输入3:
aaadbccb

样例输出

样例输出1:
1

样例输出2:
7

样例输出3:
3

来源  uva11584

分析:

当然是动规:

f[i]: 从1到i最少能划分成的个数;
 (1) 如果i到j是回文串,f[i][j]=1; 
 (2)
 f[i]= min{f[j-1]+1}  (s[j]......s[i]是回文串)

1<=i<=n  , j from i-1 down to 1;
复杂度O(n^2)
如果mark[i][j]表示i到j是不是回文串, 如何快速的推出 mark数组?


当然是再来一次动规

只有当s[i]==s[j],并且i+1到j-1是回文串时 mark[i][j]=true.
初值:
mark[i][i]=true;
一定要注意还有一个特殊情况: s[i]==s[i+1]  => mark[i][i+1]=true;

代码如下:

#include  
#include  
#include  
using namespace std;  
const int maxn=2000+5;  
char s[maxn];  
int f[maxn];  
bool mark[maxn][maxn];  
int main(){  
    int i,j,k,n,t;
	scanf("%d",&t);
	while(t--){
    	scanf("%s",s+1);  
    	n=strlen(s+1);
		memset(mark,0,sizeof(mark));
		memset(f,0,sizeof(f));
    	for(i=1;i<=n;i++){  //初值   
       	 	mark[i][i]=true;  
        	if(s[i]==s[i+1])mark[i][i+1]=true;  
    	}  
    	for(i=n;i>0;i--)   //动规求mark   
        	for(j=i+1;j<=n;j++)  
            	if(s[i]==s[j]&&mark[i+1][j-1])  
                	mark[i][j]=true;   
    	for(i=1;i<=n;i++){  //
    		f[i]=i;
    		for(j=i;j>0;j--)
    			if(mark[j][i])f[i]=min(f[i],f[j-1]+1);
    	}
    	cout<



你可能感兴趣的:(动态规划)