动态规划训练11 [String painter HDU

来源:互联网 发布:别人域名到期了能买吗 编辑:程序博客网 时间:2024/06/05 23:44

String painter

 HDU - 2476 


题意:


我认为这是一道比较难的问题,自己想了很久,没有想出来怎么做,可能是因为思维僵化吧,一直在想怎么直接的由A变到B,事实上,可以有中间桥梁连接A和B,他们之间的关系可能往往没有我们想的那么简单。

依最简单的思路,我们定义ans[i]代表区间[1...i]处,A直接变到B所需的最少次数。那么状态转移方程可以这样写

有几种情况

(1)如果strA[i] == strB[i]的话,那么存在着一个转移方程就是 ans[i] = min(ans[i],ans[i-1]);

(2)否则的话,那么第i个位置的字符,一定会被刷掉,此外,刷掉第i个位置的区间长度可能大于1,假设这个区间刷掉了区间[x,i]内的数,并把区间strA[x...i]内的数都刷成了strB[i]

这样的话就相当于把区间[x...i]由空白串直接变成strB[x...i],剩下的区间[1...x-1]可以用ans[x-1]转移过来

也就是说,转移方程写成ans[i] = min(ans[i],ans[x-1] + dp[x][i]),dp[x][i]表示从空白串直接变成strB[x][i]所需要用的最小次数。

下面我们的重要目标就是求出dp[i][j]来

其实到这里还是不太好想。

最右边的字符strB[j]一定是最先被刷出来的

(1)如果strB[i] == strA[j],那么在一开始刷刷出strB[j]的时候,顺手就可以把strB[i]也给刷出来,所以不需要额外的费用

dp[i][j] = dp[i+1][j] 

(2)然后我们把区间分成两块进行转移(非常常规的想法)

dp[i][j] = min(dp[i][j],dp[i][k]+dp[k+1][j]);


代码(注意我在前面的区间写的是全闭,而在代码里的区间写法是左闭右开):

#include <iostream>#include <cstring>#include <cstdio>#include <algorithm>using namespace std;const int MAX = 106;char strA[MAX];char strB[MAX]; int dp[MAX][MAX];int ans[MAX];int n;int main(){while(scanf("%s %s",strA,strB) != EOF){memset(dp,0,sizeof(dp));memset(ans,0,sizeof(ans));n = strlen(strA);for(int i = 0;i < n;i++) dp[i][i+1] = 1;for(int len = 2;len <= n;len++){for(int i = 0;i + len <= n;i++){dp[i][i+len] = dp[i+1][i+len] + (strB[i] == strB[i+len-1]?0:1);for(int j = i+1;j < i+len;j++){dp[i][i+len] = min(dp[i][i+len],dp[i][j]+dp[j][i+len]);} }}ans[0] = strA[0] == strB[0] ? 0:1;for(int i = 1;i < n;i++){ans[i] = dp[0][i+1];if(strB[i] == strA[i])ans[i] = min(ans[i],ans[i-1]);for(int j = 0;j < i;j++){ans[i] = min(ans[i],ans[j] + dp[j+1][i+1]);}}cout<<ans[n-1]<<endl;}return 0;}