您的位置:首页 > 大数据 > 人工智能

LA 4394 String painter

2015-10-08 23:10 507 查看
1.题目描述:点击打开链接

2.解题思路:本题是区间dp类的问题,根据题意描述,要求我们把给定的A串变成B串,每次操作时候可以选一段区间,然后将这个区间都刷成同一个字符,询问最少需要多少步。因为A串和B串部分位置可能相同,为了便于分析,让我们先忘掉A串,从一个空串考虑起。

按照以往的经验,我们可以设dp(i,j)表示把字符串A中的i...j变成字符串B中的i...j需要的最少步数。多次尝试后可以发现,如果我们刷同一个字符串,一定是希望刷的越长越好。根据题意不难得知长区间的结果依赖于短区间,那么不难得到如下的状态转移方程:

dp(i,j)=dp(i+1,j)+1; 

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

第一个方程表示单刷第i位的字符。第二个方程表示如果b[i]==b[k]时候,那么刷第k位的时候也可以同时刷第i位,因此只需要dp(i+1,k)即可表示dp(i,k)的结果了。由于长区间依赖短区间的结果,那么可以实现从小到大枚举尾部,然后再从大到小枚举头部。这样,每次需要的区间一定是之前计算过的。

计算出dp数组,还并没有得到答案。因为dp表示的是A串和B串完全不同时候,最少需要几步。接下来考虑利用dp数组和A数组来得到最终的结果。此时可以用ans[i]表示字符串A中0..i变成字符串B的0..i所需的最小步数。那么当A[i]==B[i]时候,ans[i]=ans[i-1],否则,则遍历0..i之间的所有分法。即ans[i]=min{ans[k],dp(k+1,i)}。这样,最后的答案就是ans[len-1]。

3,.代码:

#include<iostream>
#include<algorithm>
#include<cassert>
#include<string>
#include<sstream>
#include<set>
#include<bitset>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cctype>
#include<list>
#include<complex>
#include<functional>
using namespace std;

#define me(s) memset(s,0,sizeof(s))
#define rep(i,n) for(int i=0;i<(n);i++)
#define pb push_back
typedef long long ll;
typedef pair <int,int> P;

const int N=100+10;

char s1
,s2
;

int dp

;
int ans
;

int main()
{
while(~scanf("%s%s",s1,s2))
{
int len=strlen(s1);
me(dp);
for(int j=0;j<len;j++)//j是尾部
for(int i=j;i>=0;i--)//i是头部
{
dp[i][j]=dp[i+1][j]+1; //单刷第i位
for(int k=i+1;k<=j;k++)
if(s2[i]==s2[k]) //如果相等,说明i,k两位可以同时刷,更新答案
dp[i][j]=min(dp[i][j],dp[i+1][k]+dp[k+1][j]);
}
for(int i=0;i<len;i++)
ans[i]=dp[0][i];
for(int i=0;i<len;i++)
if(s1[i]==s2[i]) ans[i]=ans[i-1];//相等,那么第i位不需要改动
else for(int j=0;j<i;j++) //否则,分成2段考虑
ans[i]=min(ans[i],ans[j]+dp[j+1][i]);
printf("%d\n",ans[len-1]);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  区间dp