HDU - 2476String painter(区间DP)

本文介绍了一种通过区间动态规划解决字符串A转换为字符串B所需的最少操作次数的方法,并提供了详细的算法实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

String painter

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

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

zzzzzfzzzzz
abcdefedcba
abababababab
cdcdcdcdcdcd

Sample Output

6
7

Source

2008 Asia Regional Chengdu

Recommend

lcy

题意:

把不同字母看成看不同颜色,那么问题就是每次可以用一种颜色画一段区间
先考虑最极端的情况
把a看成是空白的(也可以理解为a与b在同一个位置完全没有公共颜色,需要全部重新涂颜色),那么把ab画成相同颜色需要的最小步数可以通过和Halloween Costumes 一样的方法处理出来,即为直接区间DP(下面会讲)
为什么?
如果C里的衣服看成颜料,每次穿衣服表示用这种颜色,每个时间点在最外面的只有一件衣服,按照时间把最外面衣服的颜色排成一排

PS放在最前面:while(~scanf(“%s%s”,a+1,b+1))
len=strlen(a+1);
个人习惯字符串开始下标为1,下标为0的也类似,改一下就可以了
for(int j=1;j<=len;++j)
{
for(int i=j;i>0;–i)
{
dp[i][j]=dp[i+1][j]+1;
for(int k=i+1;k<=j;++k)
if(b[i]==b[k])dp[i][j]=min(dp[i][j],dp[i][k-1]+dp[k+1][j]);
}
}
这样我们处理出来了所有[L,R]区间要变成和b一样的最小代价

这有什么用?
用于推广到一般情况
考虑a,b在某些位置有共同颜色的情况
只需要去掉a,b颜色相同的位置带来的影响
怎么去掉?
如果a[i]之前与b[i]都完全不同,那么1~i-1的代价就是之前dp[1][i-1]
重新开一个数组ans[i],记录a到第i个位置画成和b一个样子需要的最小代价,初始值i->1 to length ans[i]=dp[1][i];
每个位置有a[i]==b[i],a[i]!=b[i]两种情况
<1>a[i]==b[i]那就很明显了,这个位置存在与否根本不影响现在求第i位的答案,因为需要的代价和做到第i-1位是一样的ans[i]=ans[i-1]
<2>a[i]!=b[i]
如果不相等,那么是不是和之前那个问题一样了?要求[1,i]的最小代价,ans[i]=min{ans[j]+F[j+1][i]},1<=j

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=100+5;
char a[maxn],b[maxn];
int dp[maxn][maxn];
int len,ans[maxn];
int main()
{
  while(~scanf("%s%s",a+1,b+1))
  {
    len=strlen(a+1);
    memset(dp,0,sizeof(dp));
    for(int j=1;j<=len;++j)
    {
      for(int i=j;i>0;--i)
      {
        dp[i][j]=dp[i+1][j]+1;
        for(int k=i+1;k<=j;++k)
        if(b[i]==b[k])dp[i][j]=min(dp[i][j],dp[i][k-1]+dp[k+1][j]);
      }
    }

    for(int i=1;i<=len;++i)ans[i]=dp[1][i];
    for(int i=1;i<=len;++i)
    {
      if(a[i]==b[i])ans[i]=ans[i-1];
      else 
      {
        for(int j=1;j<i;++j)
          ans[i]=min(ans[i],ans[j]+dp[j+1][i]);
      }
    }
    printf("%d\n",ans[len]);
  }
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值