南邮oj 1239 字符串比较问题 字符串dp,最优状态转移

版权声明:欢迎评论交流,转载请注明原作者。 https://blog.csdn.net/m0_37809890/article/details/79969263

题目

动态规划作业题3-17

对于长度相同的两个字符串A和B,距离定义为相应位置字符距离之和.两个非空格字符的距离是它们的ASCII码之差的绝对值.空格和空格的距离为0,空格与其他字符的距离为一定值k.

字符串的扩展是指在原字符串中插入若干空格字符所产生的字符串.给定两个字符串A和B,A和B的所有长度相同的扩展中的距离最小的扩展的距离称为扩展距离,求A和B的扩展距离.

输入包括两个字符串A和B,一个整数k.
输出一个数字,A和B的最小扩展距离.

分析

刚看到这道题时懵逼了好一会,不知道它到底是在干什么.然后想到看看能不能把它转化为已有的知识.

首先想一下如果某个字符串中本来就有空格怎么办?
实际上,总能通过向另外一个字符串相应位置加空格来抵消,这个过程花费为0.

然后想一下A字符串只有一个字符的情况,它需要匹配一个B字符串中的字符,或者和空格匹配,除此之外,还有(|B|-1)*k的额外代价.如果B字符串中存在一个和A最接近且距离小于2k的,就匹配,否则全部与空格匹配.

A字符串有多个字符呢?想到这里就会发现,一个平凡的情况是全与空格匹配,代价(|A|+|B|)*k,我们需要通过确定一些匹配来使得这个值更小.
再仔细想一下,’空格’这个概念实际上是无关紧要的,一个字符可以选择和对面字符串的某个字符匹配,或者不匹配,代价直接+k就可以.

然后就是dp三连.

状态表示

dp[i][j]表示A[1]到A[i]与B[1]到B[j]的扩展距离,假定这个值已经是最优.

状态转移

如果dp[i][j]包括A[i]与B[j]匹配的情况,那么显然dp[i][j]=dp[i-1][j-1]+|A[i]-B[j]|
如果dp[i][j]中A[i]不会与B[j]匹配,那么dp[i][j]=dp[i][j-1]+k
同理如果dp[i][j]中B[j]不会与A[i]匹配,那么dp[i][j]=dp[i-1][j]+k
可以证明,dp[i][j]仅会由这三种状态转移而来.
所以不用判断条件,只需要求三者的min就好了.

边界条件

因为dp[i][j]是由dp[i-1][j-1],dp[i-1][j],dp[i][j-1]转移得到,所以如果想要进行二维循环1-i,1-j,我们需要知道dp[i][0]和dp[0][j],显然它们分别是2*i和2*j.

代码

一些代码细节问题:
排除空格我是用string读取一行然后一个一个erase的,复杂度是O(n^2),如果用char*顺序扫可以做到O(n),虽然因为dp最后的渐进复杂度都是O(n^2).
还是因为string,遍历dp时下标是1到i,1到j,这个时候只要将出现字符串的部分下标减一就好了.

/* LittleFall : Hello! */
#include <bits/stdc++.h>
using namespace std;
const int M = 1024;
int dp[M][M];

int main(void)
{
    #ifdef _LITTLEFALL_
    freopen("input.txt","r",stdin);
    #endif
    std::cin.sync_with_stdio(false); 

    string A,B;
    int k;
    getline(cin,A);
    getline(cin,B);
    cin >> k;

    for(int i=A.size();i>=0;i--)
        if(A[i]==' ') A.erase(i);
    for(int i=B.size();i>=0;i--)
        if(B[i]==' ') B.erase(i);
    int la=A.size(),lb=B.size();

    for(int i=0;i<=la;i++)
        dp[i][0]=k*i;
    for(int j=1;j<=lb;j++)
        dp[0][j]=k*j;
    for(int i=1;i<=la;i++)
    for(int j=1;j<=lb;j++)
        {
            dp[i][j]=min(dp[i-1][j]+k,dp[i][j-1]+k);
            dp[i][j]=min(dp[i][j],dp[i-1][j-1]+abs(A[i-1]-B[j-1]));
        }
    cout << dp[la][lb];

    return 0;
}

启示

如果能知道一个状态会由哪些状态转移过来,那么就可以简单地进行min/max运算了,我将这个东西称为最优状态转移.

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页