• 二维动态规划——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;
    }
  • 相关阅读:
    CSS 中z-index全解析(摘自阿里西西)
    Video标签的使用
    HTML标签解释大全
    在html中插入音频
    ABAP更改现有程序
    乱糟糟的笔记
    ABAP提示信息对话框
    【学习】几种查找增强的方法
    【学习】ABAP OLE 对EXCEL的处理
    【转载】ABAP-如何读取内表的字段名称
  • 原文地址:https://www.cnblogs.com/shuaihanhungry/p/5772059.html
Copyright © 2020-2023  润新知