• 二维动态规划——Palindrome


    Palindrome
    Description
    A palindrome is a symmetrical string, that is, a string read identically from left to right as well as from right to left. You are to write a program which, given a string, determines the minimal number of characters to be inserted into the string in order to obtain a palindrome.
    As an example, by inserting 2 characters, the string "Ab3bd" can be transformed into a palindrome ("dAb3bAd" or "Adb3bdA"). However, inserting fewer than 2 characters does not produce a palindrome.

    Input
    Your program is to read from standard input. The first line contains one integer: the length of the input string N, 3 <= N <= 5000. The second line contains one string with length N. The string is formed from uppercase letters from 'A' to 'Z', lowercase letters from 'a' to 'z' and digits from '0' to '9'. Uppercase and lowercase letters are to be considered distinct.

    Output
    Your program is to write to standard output. The first line contains one integer, which is the desired minimal number.

    Sample Input
    5
    Ab3bd

    Sample Output
    2

    状态转移方程为dp[i][j] = {min(dp[i + 1][j], dp[i][j - 1]) + 1 | str[i] != str[j], dp[i + 1][j - 1] | str[i] = str[j]},代码如下,注意其中的递归起始点是如何得到的(我们从最最边界的位置开始),空间复杂度可用滚动数组优化到O(n)。

    #include <cstring>
    #include <algorithm>
    #include <iostream>
    using namespace std;
    
    const int MAX = 5001;
    short int dp[MAX][MAX];
    
    int main() {
        int n, i, j;
        char str[MAX];
    
        cin >> n;
        cin >> str + 1;
        memset(dp, 0, sizeof(dp));
    
        for(i = n - 1; i >= 1; i--) {
            for(j = i + 1; j <= n; j++) {
                if(str[i] == str[j])
                    dp[i][j] = dp[i + 1][j - 1];
                else
                    dp[i][j] = min(dp[i + 1][j], dp[i][j - 1]) + 1;
            }
        }
        cout << dp[1][n] << endl;
    }
    

    仔细观察状态转移方程及状态转移图(假设横轴为i,纵轴为j,有效状态由1 <= i < j <= n刻画出来)可以发现当前状态只与横坐标为i或i + 1的状态有关,与其它状态无关,只可将dp[O(n)][O(n)]降低到dp[O(1)][O(n)],明确来说只需要dp[2][O(n)]。令初始k = 0,保存当前状态使用dp[k][O(n)],保存前一状态使用dp[1 - k][O(n)],交替使用k和1 - k达到滚动的效果,即滚动数组,代码如下,注意最终返回的是dp[1 - k][n],这是因为循环结束时,k对应i = 0时,那么1 - k即对应i = 1时。类似的,背包模型中很多都可以使用滚动数组优化。

    #include <cstring>
    #include <algorithm>
    #include <iostream>
    using namespace std;
    
    const int MAX = 5001;
    short int dp[2][MAX];
    
    int main() {
        int n, i, j;
        char str[MAX];
    
        cin >> n;
        cin >> str + 1;
        memset(dp, 0, sizeof(dp));
    
        int k = 0; //i = k, i + 1 = 1 - k
        for(i = n - 1; i >= 1; i--) {
            for(j = i + 1; j <= n; j++) {
                if(str[i] == str[j])
                    //dp[i][j] = dp[i + 1][j - 1];
                    dp[k][j] = dp[1 - k][j - 1];
                else
                    //dp[i][j] = min(dp[i + 1][j], dp[i][j - 1]) + 1;
                    dp[k][j] = min(dp[1 - k][j], dp[k][j - 1]) + 1;
            }
            k = 1 - k;
        }
        //cout << dp[1][n] << endl;
        cout << dp[1 - k][n] << endl;
    }
  • 相关阅读:
    Thread.join
    Thread.yield
    线程的生命周期
    HashMap底层原理
    Web Services
    Struts2框架
    hibernate乐观锁实现原理
    Hibernate框架
    oracle exp 无法导出空表
    linux 远程复制文件或文件夹
  • 原文地址:https://www.cnblogs.com/shuaihanhungry/p/5772059.html
Copyright © 2020-2023  润新知