1. 程式人生 > >臺州 OJ 1704 Cheapest Palindrome 回文 區間DP

臺州 OJ 1704 Cheapest Palindrome 回文 區間DP

rom iostream ostream 如果 main open size cstring memset

題目意思:給一個字符串和每個字母刪除、插入的代價,求把它變成回文串的最小代價

dp[i][j] 表示 區間 i~j 的子串變成回文串需要的最小代價。

設字符串 ab....cd

如果 a == d,則將其變成回文串的最小代價就是將 b....c 變成回文串

如果 a != d,考慮如下四種情況

在左邊插入一個等於 d 的字符變成 dab....cd,則將其變成回文串的代價是將 ab....c 變成回文串的代價,加上插入 d 的代價。

在將左邊的 a 刪除變成 b....cd,則將其變成回文串的代價是將 b....cd 變成回文串的代價,再加上刪除 a 的代價。

右邊的情況一樣。

取上面四種情況代價最小的

代碼:

#include <iostream>
#include <cstring>
using namespace std;

const int MAX = 2005;

int dp[MAX][MAX];        //i....j 變成回文的最小代價 
int v1[130];            //增加代價 
int v2[130];            //刪除代價 
char s[MAX];
int n, m;

int main(){
//    freopen("input.txt", "r", stdin);
    
    cin >> n >> m;
    cin 
>> s+1; // getchar(); for(int i=1; i<=n; i++){ char ch; cin >> ch; cin >> v1[(int)ch] >> v2[(int)ch]; } //DP memset(dp, 0, sizeof(dp)); for(int len=1; len<=m; len++){ for(int i=1; i+len-1<=m; i++){ int
j = i + len - 1; if(s[i] == s[j]) //如果兩端點相等 dp[i][j] = dp[i+1][j-1]; //等於把兩頭去掉後中間的串變成回文的代價。(如果 i == j 或 i+1 == j ,此時 dp[i+1][j-1] = 0 else{ int left = min(dp[i+1][j] + v2[s[i]], dp[i][j-1] + v1[s[j]]); //如果增加或刪除左邊的 int right = min(dp[i][j-1] + v2[s[j]], dp[i+1][j] + v1[s[i]]); //如果增加或刪除右邊的 dp[i][j] = min(left, right); } // cout << i << " " << j << " " << dp[i][j] << endl; } } cout << dp[1][m]; return 0; }

臺州 OJ 1704 Cheapest Palindrome 回文 區間DP