qsc54(区间dp)

题目链接:http://qscoj.cn/problem/54/

 

题意:中文题诶~

 

思路:区间dp

我们可以用dp[i][j]存储区间[i, j]最少需要的打印次数,若没有相同的字母,那么需要的打印次数为dp[i+1, j]+1 (尾字符放在外层循环枚举,首字符放在内一层循环枚举,至于原因在后面会说明)。我们再枚举一个k为[i, j]的中间节点,将[i, j]分成两个子串,由子串的最优解状态转移得到当前串的最优解;那么有[i, j]被分解成[i, k], [k+1, j],

所以有: dp[i][j]=dp[i, k] + dp[k+1][j];若str[k]==str[j],则dp[i, k]==dp[i+1, k] ,所以动态转移方程式为dp[i][j]=min(dp[i][j], dp[i+1][k]+dp[k+1][j]);

注意这里k>i,所以 i 必须放到内循环,不然用未更新的dp[k+1][j]去更新dp[i][j]自然是不能保证得到正确答案;其实就是枚举每个尾节点的所有情况啦。

 

代码:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #define MAXN 60
 5 using namespace std;
 6 
 7 char str[MAXN];
 8 int dp[MAXN][MAXN];//dp[i][j]存储区间[i,j]至少要打印多少次
 9 
10 int main(void){
11     while(~scanf("%s", str)){
12         memset(dp, 0, sizeof(dp));
13         int len=strlen(str);
14         for(int i=0; i<len; i++){//i为尾字符
15             for(int j=i; j>=0; j--){//j为头字符
16                 dp[j][i]=dp[j+1][i]+1;//若没有重复的字符,那么[i,j]可以由[i+1,j]+1得到
17                 for(int k=j+1; k<=i; k++){
18                     if(str[k]==str[j]){//枚举中间字符,若str[k]==str[j],则dp[i][k]==dp[i+1][k]
19                         dp[j][i]=min(dp[j][i], dp[j+1][k]+dp[k+1][i]);
20                     }
21                 }
22             }
23         }
24         printf("%d\n", dp[0][len-1]);
25     }
26     return 0;
27 }
View Code

 

posted @ 2017-03-21 22:15  geloutingyu  阅读(346)  评论(0编辑  收藏  举报