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

题目

动态规划作业题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运算了,我将这个东西称为最优状态转移.

你可以使用Crypto++库中的RSA类来导入RSA公钥/私钥的字符串表示。下面是一个简单的示例代码: ```c++ #include <iostream> #include <string> #include <cryptopp/rsa.h> #include <cryptopp/base64.h> using namespace CryptoPP; int main() { // RSA keys in PEM format std::string publicKeyPEM = "-----BEGIN PUBLIC KEY-----\n" "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvRJ9YmJ9A0seV0bSf+I6\n" "n5i6dF6qXl5Hf8b0KJvJ7eN0yTnE4t5rKQYdM+DLg1yXz+4kWv8xgJxJW9Q2gY7L\n" "wNqROnFJZrOq6zZVrWXfR4gWVv8grl2PZl6vQfGbdzPd2BhLW1QOyPZfGy1CCoMg\n" "FQd6ZqBx1UJHsUSx/PnV0i35S8zO7Zq9UxOYbRr9SiCsTJ0FNLwPz7CkC5u3VJ5D\n" "z5z2K7U0fGkO+8fOc5Qv2JUqKd6sN2oT+18+eVf/lvtlQ4U3aXyKZB7u0k8T3xKx\n" "3J2r3x4y+o9B3fz1aV0R/5N5Iz2Kt6gJyJmJyNfh0T+D5JLZL8o+Oq8rD8/8mLgV\n" "XQIDAQAB\n" "-----END PUBLIC KEY-----\n"; std::string privateKeyPEM = "-----BEGIN PRIVATE KEY-----\n" "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCuN1Qa1iRQ9ZvZ\n" "iFfZjzKfKXk9X5Rq8Dp4CCVt1LJbXG8oU1Kd7UeJb+JyQrK+D1hViDUKvC4pDvZL\n" "7Wv8wzZ1mJN+3M+Vc7dqSaTr0z+U4d3ZKQKj1UjF9/3Ud/HXw6Ez84Zx5fX1U7P\n" "3u9Qo+6g0cva0tYcZ8E4m8osjzOZn3n5Z+qoDZ2IuoktDjQOdT7vZJc7JmLQ+6U\n" "Gyf8B4j0c6V7iJ0oqOeq27m2xY6xu9gKwDvZl9zJrFv6f9JQy6yY5ZjXVItK8o+\n" "x3DfX+eD8XO7Z0f1wO3J5lXgBuJop4B3PzZPmZw3jwN3LZwU7hAqjWQvLj5r+DqR\n" "KwvS6TJnAgMBAAECggEBAJv9zZ1N9sN7E+gTt9y/7xFG2PjgB9VjYWg6bd4QKpRq\n" "zGJNj2n8q6k8l7k2uT6sRcO5RhS8bQpO4iLl3GJXZr5kjC0Z/1kE1p4H8Y9e5bDh\n" "gNl3ZnK3Wpli8q7KqUjOY8j6Ktj7+vZnT3sW6v/qpIbQgBn7d3q0qsqzjTm8c5f\n" "V3JzUJqkVJqX1mJmJd6tZslpO8mJyZL/vkC4KszkQeE8xKu6sIiA4r6l5e0+OJ8M\n" "8XmXhV8D8ZcHgKvq7qrBvFq5Xv2mHsLdQO+J7uNLC3iQzY3u4jB6Gk8fN7N3e3jv\n" "dDmf8P0l7dOj6q5sZtqoK6fJjW+PcVnC8KzXUy4YrtkCgYEA3g9W5c7J8KmX3xSU\n" "2p/7VfGzBYC7J1Ll1fz4qWf3XZ2VQF7q6yRrA5X+H2GkZiB3vL8/3gOeO3WuGnI0\n" "bJr1lOY9xMvQj7a6KdC5h4Wvmt3qqh6VdQw7dFx8fJ8x5RQwReOuyZ9nEE5Vf+en\n" "cRg9Uk9LQl3rZ4cazH7c+Lkrj2ECgYEAzL4u8eJ5gCpUvJZJyCmlrJX0GryL1wzE\n" "5zO8m1tjwg1YONyJvR4g4bd7p+56q6v3wTzoumH6x3AWDZC8Z6Jr6i4a8+cnl+9M\n" "P+Jr5Lr2fN2Y7w3dFzHhY5NIR0ZxTQJdC5Jp+el1+Kg2y4eFJZpQz0ueH2Jy6wuz\n" "zqJUQY2RmXUCgYEAwYjQg1FnKPGvJlRrXwL9cO4I3W0gx/kD+LpT8aEguJlRf4uS\n" "ZyN8a+xLZbGzWc5wKT9z3whYf4fXf4aFh2U+ZQzXG7yUa5KdNf7xvP8QXa6omQY0\n" "sQO2e1+Vc1r7h2e0HNY0U6E0g+7l7MBZv5lZP6XG7HdY5k8n1UdbvR9uGkECgYEA\n" "xAIlWc+0qLQUjY7t2sqHjzJ3nV2GxMvW0G9fZgD6loQWtKX2Y7r/x6WLZ9Smc5ZQ\n" "4QJ1l0sT1q2YKqCwR1u+2J9lX8Pp17FZK8Xvq8kPT9lQK9o3+JvUqPvX6xrmJ2mK\n" "R7uxvYv+ZzL2R9gkt/6g1QH0aRZzZj0+6+J5PfWen9sCgYEA7fQxJYJdQdUgJvZL\n" "gH2Y1o5LJ5W1N3v9zQJLJGJ1Tt7TfB3gXzOzL/hsW68Uzr+1JqP6e9LTk5OuWVQG\n" "yR7zFv3p6K5tqT2Z0OJdS4xVw/2zB5YzJiK6I6b5aMZr9o2ZtW/0A1m5RcU6bJSo\n" "Vz5Q5O1ZoD7JdS3d+6iNq+f8dQ==\n" "-----END PRIVATE KEY-----\n"; // Base64 decode the PEM strings std::string publicKeyStr, privateKeyStr; StringSource(publicKeyPEM, true, new Base64Decoder(new StringSink(publicKeyStr))); StringSource(privateKeyPEM, true, new Base64Decoder(new StringSink(privateKeyStr))); // Load the keys from the decoded strings RSA::PublicKey publicKey; RSA::PrivateKey privateKey; StringSource(publicKeyStr, true, new PEMDecoder(new StringSink(publicKey))); StringSource(privateKeyStr, true, new PEMDecoder(new StringSink(privateKey))); return 0; } ``` 在这个示例中,我们将PEM格式的RSA公钥/私钥字符串进行Base64解码,然后使用Crypto++库中的PEMDecoder类将它们加载到RSA::PublicKey和RSA::PrivateKey对象中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值