二维动态规划——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;
}
原文地址:https://www.cnblogs.com/shuaihanhungry/p/5772059.html