T1015 Letter-moving Game (35 point(s))

T1015 Letter-moving Game (35 point(s))

题干

Here is a simple intersting letter-moving game. The game starts with 2 strings S and T consist of lower case English letters. S and T contain the same letters but the orders might be different. In other words S can be obtained by shuffling letters in String T. At each step, you can move one arbitrary letter in S either to the beginning or to the end of it. How many steps at least to change S into T?

Input Specification:

Each input file contains one test case. For each case, the first line contains the string S, and the second line contains the string T. They consist of only the lower case English letters and S can be obtained by shuffling T’s letters. The length of S is no larger than 1000.

Output Specification:

For each case, print in a line the least number of steps to change S into T in the game.

Sample Input:

iononmrogdg
goodmorning

Sample Output:

8

Sample Solution:

(0) starts from iononmrogdg
(1) Move the last g to the beginning: giononmrogd
(2) Move m to the end: giononrogdm
(3) Move the first o to the end: ginonrogdmo
(4) Move r to the end: ginonogdmor
(5) Move the first n to the end: gionogdmorn
(6) Move i to the end: gonogdmorni
(7) Move the first n to the end: googdmornin
(8) Move the second g to the end: goodmorning

题目限制条件

  • 时间限制:200ms
  • 内存限制:64MB

题目大意

输入两个仅由小写字母构成的字符串S,T,且题目保证S恰好是将T中的字母随机打乱顺序得到的。现在问题来了:如果我们每次操作能够将S中的一个字母移动到S的开头末尾,那么字符串S最少经过多少次可以被还原为T?

本题考察知识点

动态规划(Dynamic Processing, DP)

解题思路

我们观察到第一步将S中的第一个"g"移动到了开头。在此我们应当先思考三个问题:

  • 移动这个"g"对最终的结果有什么影响?事实上,我们可以看到,在移动之前,S中出现了T的子串"ood"的子序列"iononmrogdg";经过这一步移动之后,S中出现了单词"good"的子序列"giononmrogd"。而后续的每次移动均能增加这样的子序列的长度,使所有字母“越来越紧凑”。

  • 为什么移动第一个"g"而不是第二个"g"?事实上,第一步移动第二个"g"并不会对最终的结果产生任何影响。因为在后续移动的过程中,肯定有一次移动是将另外一个没有移动过的"g"移动到末尾。

  • 为什么要移动8次?因为在移动之前,T中存在长度为3的子串"ood",它也恰好是S的子序列。随后的每一次移动都会增加这个子序列的长度,直到子序列的长度等于T的长度,此时S和T相等。

综上,我们已经有了初步的思路。我们需要统计符合以下要求的字符串T’的最大长度:

  • T’是T的子串
  • T’是S的子序列

因此我们可以搜索T的所有子串,针对每个子串判断一下它是否是S的子序列。假设dp[i][j]是字符串T中从下标i开始长度为j的子串作为S的子序列在S中的结束位置(如果不是S的子序列则值为-1),则可构造如下的状态转移方程:
请添加图片描述

其中k是从位置dp[i][j-1]+1开始往后数,字符T[i+j-1]第一次出现的位置(如果没有出现则值为-1)。

在计算dp数组的所有可能值的同时,记录下我们在计算过程中遇到过的最大的k。最后用k减去原字符串S的长度,就得到题目所要求的结果。

AC代码

#include "bits/stdc++.h"

std::string S, T;
typedef long long ll;
#define maxn 1005

void init() {

}

void read() {
    std::cin >> S >> T;
}

//FOendpos_in_S[i][j]表示:字符串T中从下标i开始长度为j的子串作为S的子序列在S中的结束位置(如果不是S的子序列则值为-1)
int FOendpos_in_S[maxn][maxn];


int compute() {
    int ans = 1;
    int char2FOpos[256];
    memset(char2FOpos, -1, sizeof char2FOpos);
    memset(FOendpos_in_S, -1, sizeof FOendpos_in_S);
    for (int i = 0; i < S.length(); ++i) {
        if (char2FOpos[S[i]] == -1)
            char2FOpos[S[i]] = i;
    }
    for (int i = 0; i < T.length(); ++i) {
        FOendpos_in_S[i][1] = char2FOpos[T[i]];
    }
    for (int l = 2; l <= S.length(); ++l) {
        for (int i = 0; i <= S.length() - l; ++i) {
            if (FOendpos_in_S[i][l - 1] != -1) {
                auto pos = std::find(S.begin() + FOendpos_in_S[i][l - 1] + 1, S.end(), T[i + l - 1]);
                if (pos == S.end())
                    FOendpos_in_S[i][l] = -1;
                else {
                    FOendpos_in_S[i][l] = pos - S.begin();
                    ans = std::max(ans, l);
                }
            }
        }
    }
    return ans;
}

void solve() {
    printf("%d", S.length() - compute());
}

int main() {
//    freopen("Depressant.txt", "r", stdin);
    init();
    read();
    solve();
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值