HDU2476(区间DP)详解

本文介绍了一种将一个字符串通过最少次数的操作转换为另一个字符串的算法。该算法利用动态规划原理,通过构建状态转移方程实现最优路径寻找。文章详细解析了算法的实现过程,并通过实例演示了如何计算操作次数。

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

题目大意:每次输入两串字符串,把第一串变成第二串,但是你每次只能把字符串中一段连续的子串变成一同一种字符串,问你总共需要几次才能完成?

输入要求:两串字符,字符串最长为100。

输出要求:需要改变的次数。

样例解释:
开始zzzzzfzzzzz
第一次:aaaaaaaaaaa
第二次:abbbbbbbbba
第三次:abcccccccba
第四次:abcdddddcba
第五次:abcdeeedcba
第六次:abcdefedcba
结束:abcdefedcba
开始:abababababab
第一次:ccccccccccb
第二次:cdddddddddcb
第三次:cdcccccccdcb
第四次:cdcdddddcdcb
第五次:cdcdcccdcdcb
第六次:cdcdcdcdcdcb
第七次:cdcdcdcdcdcd
结束:cdcdcdcdcdcd

思路引导:刚开始先求出由空串到str2总共需的次数,存在dp中,然后在下面通过str1和str2的比较来进一步判断。

程序详细解释:我的字符串是从1开始的,这题的难点无非就是那段空字符串到str2的三个for循环比较难理解,其实我是模拟才看懂的 ~我以第二个样例为示范。
来先把程序看一遍
…………..

   for(j=1;j<=len;j++)
        {
            for(i=j;i>=1;i--)
            {
                dp[i][j]=dp[i+1][j]+1;
                for(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]);
                }
            }
        }

好我们开始模拟,一定要记住str2,也就是目标串,还有程序~dp初始值都是零~
j=1 i=j=1 dp[1][1]=dp[2][1]+1=1
k=i+1=2 k<=1 不符合
j=2 i=j=2 dp[2][2]=dp[3][2]+1=1
k=3 k<=2 不符合
j=2 i–=1 dp[1][2]=dp[2][2]+1=2
k=2 k<=2 符合 str2[1]!=str2[2]【c!=d】
j=3 i=j=3 dp[3][3]=dp[4][3]+1=1
k=i+1=4 4<=3 不符合
j=3 i–=2 dp[2][3]=dp[3][3]+1=2
k=i+1=3 3<=3 符合 str2[2]!=str2[3]【d!=c】
j=3 i–=1 dp[1][3]=dp[2][3]+1=3
k=i+1=2 2<=3 符合 str2[1]!=str[2] 【c!=d】
k++=3 3<=3 符合 str2[1]==str2[3] 【c==d】
dp[1][3]=min(dp[1][3],dp[2][3]+dp[4][3])【min(3,2+0)】=2
j=4 i=j=4 dp[4][4]=dp[5][4]+1=1
k=i+1=5 5<=4 不符合
j=4 i–=3 dp[3][4]=dp[4][4]+1=1
k=i+1=4 4<=4 符合 str2[3]!=str2[4]【c!=d】
j=4 i–=2 dp[2][4]=dp[3][4]+1=2
k=i+1=3 3<=4 符合 str2[2]!=str2[3]【f!=c】
k++=4 4<=4 符合 str2[4]==str2[2] 【d==d】
dp[2][4]=min(dp[2][4],dp[3][4]+dp[5][4)【min(2,2+0)】=2
j=4 i=1 dp[1][4]=dp[2][4]+1=3
k=i+1=2 2<=4 符合 str2[1]!=str2[2]【c!=d】
k++=3 3<=4 str2[1]==str2[3] 【c==c】
dp[1][4]=min(dp[1][4],dp[2][3]+dp[4][4])【min(3,2+1)】=3
K++=4 4<=4 str2[1]!=str2[4]【c!=d】
…………..
通过上面的模拟我们很容易发现dp[i][j]=dp[i+1][j]的作用第一遍很明显就是让dp[x][x]=1,因为第一遍时i=j,这是因为你要把一个空白字符串刷成str2你最少需要刷一遍,外面两个for循环的作用是先求出不管str2[i]==str2[k]可以一遍刷这些情况,最少需要的值,最里面的k循环是求当有两处字符串相同时,可以一遍刷的次数,通过min(dp[i][j],dp[i+1][k]+dp[k+1][j]),这个dp[i+1][k]+dp[k+1]k[j]式子的含义是,因为str2[i]=str2[k]相同,所以刷str2[k]时就已经把str2[i]刷过了所以dp[i+1][k],至于为什么分成这两半,我还没有完全理解。。。。正在写~
代码是我后来修改的,更加易于理解,与上面都略有区别

#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <math.h>

using namespace std;
int dp[105][105];
int Max[105];
char str1[105];
char str2[105];
#define INF 0x3f3f3f3f
int main()
{
    while(scanf("%s%s",str1+1,str2+1)!=EOF)
    {
        memset(dp,0,sizeof(dp));
        int i,j,k;
        int len=strlen(str1+1);
        int L;
        for(i=1;i<=len;i++)
        {
            for(j=i;j<=len;j++)
            {
                dp[i][j]=INF;
            }
        }
        for(L=1;L<=len;L++)
        {
            for(i=1;i<=len-L+1;i++)
            {
                j=i+L-1;
                dp[i][j]=dp[i+1][j]+1;
                for(k=i+1;k<=j;k++)
                {
                    if(str2[k]==str2[i])
                        dp[i][j]=min(dp[i][j],dp[i+1][k]+dp[k+1][j]);
                }
            }
        }
        for(i=1;i<=len;i++)
            Max[i]=dp[1][i];
        for(i=1;i<=len;i++)
        {
            if(str1[i]==str2[i])
                Max[i]=Max[i-1];
            else
            {
                for(j=i-1;j>=1;j--)
                    Max[i]=min(Max[i],Max[j]+dp[j+1][i]);
            }
        }
        printf("%d\n",Max[len]);
    }
    return 0;
}

本博客与lyjzsyzlt为同学~相同文章是一起写的~
涵哥出手,必属精品~

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值