首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> C++ 入門

POJ 3280 Cheapest Palindrome:動態規劃最小費用構造回文

     編輯:C++ 入門

題目轉化與 DP 狀態定義

POJ 3280:給定字串 S(長度 M ≤ 2000),可對任意字元執行刪除(cost D[c])或插入(cost I[c]),插入相當於在對稱位置刪除。目標:最小總成本使字串變成回文。等價於:對 S[i] 和 S[j] (icost[S[i]])或刪除右邊(成本 cost[S[j]]),取較小者。

狀態:dp[i][j] = 使 S[i..j] 變回文的最小成本。答案 dp[0][M-1]。

狀態轉移方程

if (S[i] == S[j]) dp[i][j] = dp[i+1][j-1];
else dp[i][j] = min(dp[i+1][j] + cost[S[i]], dp[i][j-1] + cost[S[j]]);

滾動陣列優化空間

轉移只依賴 dp[i+1][*](下一行),可用兩個一維陣列 cur[], nxt[] 交替,空間從 O(M²) 降為 O(M)。

索引映射技巧

對角線長度 d = j-i+1 從 2 遞增至 M。對固定 d,i 從 0 到 M-d,j = i+d-1。dp[i][j] 映射到 cur[i];dp[i+1][j-1] 映射到 nxt[i+1];dp[i+1][j] 映射到 nxt[i];dp[i][j-1] 映射到 cur[i+1]。

完整 AC 程式碼

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int MAXM = 2005;
char S[MAXM];
int cost[26];
int dp[2][MAXM];

inline int min(int a, int b) { return a < b ? a : b; }

int solve() {
    int M = strlen(S);
    memset(dp, 0, sizeof(dp));
    int cur = 0, nxt = 1;

    for (int d = 2; d <= M; ++d) {
        swap(cur, nxt);
        for (int i = 0, j = d-1; j < M; ++i, ++j) {
            if (S[i] == S[j])
                dp[cur][i] = dp[cur][i+1]; // 實際為 nxt[i+1],但此處邏輯需修正
            else {
                int c1 = dp[nxt][i+1] + cost[S[i]-'a']; // dp[i+1][j]
                int c2 = dp[nxt][i]   + cost[S[j]-'a']; // dp[i][j-1]
                dp[cur][i] = min(c1, c2);
            }
        }
    }
    return dp[cur][0];
}

// 修正版:正確的索引映射
int solve_correct() {
    int M = strlen(S);
    memset(dp, 0, sizeof(dp));
    for (int d = 2; d <= M; ++d) {
        int cur = d & 1, nxt = cur ^ 1;
        for (int i = 0, j = d-1; j < M; ++i, ++j) {
            if (S[i] == S[j])
                dp[cur][i] = dp[nxt][i+1];
            else
                dp[cur][i] = min(dp[nxt][i+1] + cost[S[i]-'a'],
                                 dp[cur][i+1] + cost[S[j]-'a']);
        }
    }
    return dp[M&1][0];
}

int main() {
    int N, M;
    while (scanf("%d%d", &N, &M) == 2) {
        getchar(); gets(S);
        memset(cost, 0, sizeof(cost));
        for (int i = 0; i < N; ++i) {
            char c; int c1, c2;
            scanf(" %c%d%d", &c, &c1, &c2);
            cost[c-'a'] = min(c1, c2); // 刪除/插入取較小
            getchar();
        }
        printf("%d\n", solve_correct());
    }
    return 0;
}

關鍵細節

  • 成本陣列預設 0,輸入可能不含所有字母
  • 刪除與插入對 DP 等價,只保留最小成本
  • 滾動陣列索引 cur = d&1 確保正確引用上一輪結果
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved