hdu String painter(dp)

来源:互联网 发布:mac查看进程 编辑:程序博客网 时间:2024/05/15 15:25

String painter

Time Limit: 5000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1075 Accepted Submission(s): 420


Problem Description
There are two strings A and B with equal length. Both strings are made up of lower case letters. Now you have a powerful string painter. With the help of the painter, you can change a segment of characters of a string to any other character you want. That is, after using the painter, the segment is made up of only one kind of character. Now your task is to change A to B using string painter. What’s the minimum number of operations?

Input
Input contains multiple cases. Each case consists of two lines:
The first line contains string A.
The second line contains string B.
The length of both strings will not be greater than 100.

Output
A single line contains one integer representing the answer.

Sample Input
zzzzzfzzzzzabcdefedcbaababababababcdcdcdcdcdcd

Sample Output
67

Source
2008 Asia Regional Chengdu

Recommend
lcy
 
这道题想了很久。
首先突破的是,想出这道题是区间的动态规划。
区间的动态规划,可以按区间长度循环,从小到大
然后想出,每次刷的区间,肯定不是相交的关系,要么包含,要么相离
接着看出,对每个区间,首尾字母(在目标串中的)一定是相同的,否则这个区间包含最后那个字母是没有意义的
但是,接下来问题就来了,因为每次刷了一个区间后,在求这个被刷区间内的小区间时,原来的dp值已经无效了
因为这时不是从初始串变到目标串,而是从被刷后的串变到目标串。
这样难道要再加一维状态记录当前串是哪些字母吗?可是这样感觉做不下去了
这里实在想不下去了,搜了解题报告后发现一种思路:
先不管初始串,把题目改为按照原来的规则,直接构造一个目标串,问最少需要几步?
这样,之前卡住的不断变化的串就不用考虑了,因为我不考虑当前串是什么,只考虑哪一部分已经匹配目标串
于是,用dp[i][j]记录从把i~j区间的空串变化到目标串,
初始化方程:dp[i][j] = dp[i+1][j] + (t[i]==t[j]?0:1);
//0的意思是,i不用考虑了,因为可以在刷j时“顺便”把它刷了,注意
//if(t[i] == t[j])  dp[i][j] = dp[i+1][j-1]+1是不对的,这样答案是偏大的
变化方程:if(t[i] == t[k])                      dp[i][j] = min(dp[i][j],dp[i+1][k]+dp[k+1][j]);
这样有了dp值后,再来求这个题目的ans,ans[i]代表0~i初始串变到目标串所需的最少步数
对ans[i],枚举出所有的情况即可
详见代码:
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;int dp[105][105];int ans[105];int main(){    char s[105],t[105];    while(scanf("%s%s",s,t) != EOF){        int n = strlen(s);        for(int k = 1;k <= n;k++){            for(int i = 0;i < n-k+1;i++){                if(k == 1)  dp[i][i+k-1] = 1;                else dp[i][i+k-1] = dp[i+1][i+k-1] + (t[i]==t[i+k-1]?0:1);                for(int j = i+1;j < i+k-1;j++){                    if(t[i] == t[j])                        dp[i][i+k-1] = min(dp[i][i+k-1],dp[i+1][j]+dp[j+1][i+k-1]);                }            }        }        for(int i = 0;i < n;i++){            ans[i] = dp[0][i];            if(s[i] == t[i])    ans[i] = ans[i-1];            for(int j = 0;j < i;j++){                ans[i] = min(ans[i],ans[j]+dp[j+1][i]);            }        }        cout << ans[n-1] << endl;    }    return 0;}