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 }
我就是我,颜色不一样的烟火 --- geloutingyu