UVALive - 4394 String painter DP
2015-03-04 00:12
260 查看
题目大意:给出两个字符串,可以对将第一个字符串进行操作,操作的过程是将第一个字符串中的一个连续的子串换成同一个字母,问至少需要多少次操作才能使第一个字符串变成第二个字符串
解题思路:这里两种解法:
第一个解法(比较繁琐):设dp[i]为扫描到字符串的第i个字符时需要进行操作的最小次数。这里有两种情况
1.str1[i] == str2[i],这样的话就不需要对第i个进行操作了,直接dp[i] = (i == 0 ? 0 : dp[i-1])
2.str1[i] != str2[i],从左到右扫描,如果str2[j] == str2[i],就从这个j处进行切割,将其分成两个部分,[0,j-1]和[j,i],这样的话dp[i] = min(dp[i],dp[j-1]+statu[j+1][i-1][str2[j]-'a']+1),还要考虑到j是0的情况,当j == 0,dp[i] = min(dp[i],statu[j+1][i-1][str2[j]-'a']+1)
这里解释一下这个statu数组和后面的1的意思,statu[i][j][k]表示将第一个字符串从第i个字符到第j个的字符都为k的子串变成相应的第二个字符串的子串需要操作的最少次数,为什么会从第i个字符到第j个字符都是字符k呢,因为头尾相同的情况下,可以将中间部分变成和头尾相同的字符,这样可以减少一次操作,所以后面要再statu后面加上了1,表示进行了一个前面所说的操作了,具体看代码,写得比较急,如果写错的话请见谅
这里的转换就和上面的差不多,就不详写了,不懂请看代码。用ans[i]表示第一个字符串的前i个字符变成第二个字符串的前i个字符的操作次数。
首先ans[i] = dp[0][i],这是最差的状态
然后如果str1[i] == str2[i], ans[i] = min(ans[i], (i == 0 ? 0:ans[i-1]))
最后再进行区间分段,求出最优的方法,ans[i] = min(ans[i],ans[j] + dp[j+1][i])
解题思路:这里两种解法:
第一个解法(比较繁琐):设dp[i]为扫描到字符串的第i个字符时需要进行操作的最小次数。这里有两种情况
1.str1[i] == str2[i],这样的话就不需要对第i个进行操作了,直接dp[i] = (i == 0 ? 0 : dp[i-1])
2.str1[i] != str2[i],从左到右扫描,如果str2[j] == str2[i],就从这个j处进行切割,将其分成两个部分,[0,j-1]和[j,i],这样的话dp[i] = min(dp[i],dp[j-1]+statu[j+1][i-1][str2[j]-'a']+1),还要考虑到j是0的情况,当j == 0,dp[i] = min(dp[i],statu[j+1][i-1][str2[j]-'a']+1)
这里解释一下这个statu数组和后面的1的意思,statu[i][j][k]表示将第一个字符串从第i个字符到第j个的字符都为k的子串变成相应的第二个字符串的子串需要操作的最少次数,为什么会从第i个字符到第j个字符都是字符k呢,因为头尾相同的情况下,可以将中间部分变成和头尾相同的字符,这样可以减少一次操作,所以后面要再statu后面加上了1,表示进行了一个前面所说的操作了,具体看代码,写得比较急,如果写错的话请见谅
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; #define maxn 110 #define INF 0x3f3f3f3f char str1[maxn], str2[maxn]; int statu[maxn][maxn][30], dp[maxn]; int DP(int start, int end, int c) { if(start > end) return 0; if(statu[start][end][c] != INF) return statu[start][end][c]; if(start == end) { if(str2[start] - 'a' == c) statu[start][end][c] = 0; else statu[start][end][c] = 1; return statu[start][end][c]; } for(int i = start; i <= end - 1; i++) statu[start][end][c] = min(statu[start][end][c],DP(start,i,c)+DP(i+1,end,c)); if(str2[start] == str2[end]) { if(str2[start] - 'a' == c) statu[start][end][c] = min(statu[start][end][c],statu[start+1][end-1][c]); else statu[start][end][c] = min(statu[start][end][c],DP(start+1,end-1,str2[start]-'a')+1); } return statu[start][end][c]; } int main() { while(scanf("%s%s",str1, str2) != EOF) { int len = strlen(str2); memset(statu,0x3f,sizeof(statu)); memset(dp,0x3f,sizeof(dp)); for(int i = 0; i < len; i++) { if(str1[i] == str2[i]) { if(i == 0) dp[i] = 0; else dp[i] = dp[i-1]; } else { for(int j = i; j >= 0; j--) if(str2[i] == str2[j]) { if(j == 0) dp[i] = min(dp[i],DP(j+1,i-1,str2[i]-'a')+1); else dp[i] = min(dp[i],dp[j-1]+DP(j+1,i-1,str2[i]-'a')+1); } } } printf("%d\n",dp[len-1]); } return 0; }解法二:(区间DP)可以想将一个空字符串变成第二个字符串,看中间的操作需要进行多少次。用dp[i][j]表示将一个空字符串变成第二个字符串的第i个字符到第j个字符的子串的操作次数。
这里的转换就和上面的差不多,就不详写了,不懂请看代码。用ans[i]表示第一个字符串的前i个字符变成第二个字符串的前i个字符的操作次数。
首先ans[i] = dp[0][i],这是最差的状态
然后如果str1[i] == str2[i], ans[i] = min(ans[i], (i == 0 ? 0:ans[i-1]))
最后再进行区间分段,求出最优的方法,ans[i] = min(ans[i],ans[j] + dp[j+1][i])
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; #define maxn 110 #define INF 0x3f3f3f3f int dp[maxn][maxn], ans[maxn]; char str1[maxn], str2[maxn]; void DP(int i, int j) { if(i == j) { dp[i][j] = 1; return ; } dp[i][j] = dp[i+1][j] + 1; for(int k = i + 1; k <= j; k++) { if(str2[i] == str2[k]) dp[i][j] = min(dp[i][j],dp[i+1][k]+dp[k+1][j]); } } int main() { while(scanf("%s%s", str1, str2) != EOF) { int len = strlen(str2); memset(dp,0,sizeof(dp)); for(int i = 0; i < len; i++) for(int j = 0; i + j < len; j++) DP(j,i+j); for(int i = 0; i < len; i++) { ans[i] = dp[0][i]; if(str1[i] == str2[i]) ans[i] = min(ans[i],(i == 0 ? 0:ans[i-1])); for(int j = 0; j < i ; j++) ans[i] = min(ans[i],ans[j]+dp[j+1][i]); } printf("%d\n",ans[len-1]); } return 0; }
相关文章推荐
- uvalive 4394 string painter (序列dp)
- uva live 4394 String painter 区间dp
- uva live 4394 String painter 区间dp
- HDU 2476 | UVALive 4394 - String painter (区间DP)
- uva live 4394 String painter 间隔dp
- UVA Live Archive 4394 String painter(区间dp)
- UVA 4394 - String painter(字符串区间DP)
- la 4394 string painter 区间dp
- LA 4394 String painter 区间DP -
- UVA 1437 String painter(区间dp)
- uvalive4394(区间dp)
- dp 专题系列(二):LA3983 Robotruck,LA4794 Sharing Chocolate,LA4394 String Painter,LA4327 Parade,Uva 10817
- UVALIVE4394,区间DP好题
- uva live 3516 Exploring Pyramids 区间DP
- UVALIVE 3516(DP)
- hdu 2476 String painter 区间dp
- UVALive 6257 Chemist's vows --一道题的三种解法(模拟,DFS,DP)
- UVALive 5002 The Queue (树形Dp)
- uva1437 String painter
- C - Permutation Counting UVALive - 5092 dp