区间DP Cheapest Palindrome

题目链接:
POJ-3280
大意:
给一个串,给出每个字母删去和增加的代价(cost) 要求使之变成回文串的最小代价

分析:
考虑区间 DP 方程, dp(i,j) 表示从 i 到 j 的最小代价,那么 i 到 j 已经考虑完回文了
对于 dp(i,j) 方向有 dp(i+1,j) 和 dp(i,j-1) 两个,分别从增加和删除两种方式中取小值

dp方程:

if s[i] == s[j]
    dp[i][j]=dp[i+1][j-1];
else 
    dp[i][j]=
    min{
        dp[i+1][j]+min(a[s[i]],d[s[i]]);
        dp[i][j-1]+min(a[s[j]],d[s[j]]);
    }        

具体实现:

#include<iostream>
#include<string>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<map>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair <int, int> pii;
#define mem(s,t) memset(s,t,sizeof(s))
#define D(v) cout<<#v<<" "<<v<<endl
#define inf 0x3f3f3f3f
#define pb push_back
#define mk make_pair
#define fi first
#define se second

#pragma warning(disable:4996)
#pragma comment(linker, "/STACK:336777216")

//#define LOCAL
const int mod = 1e9 + 7;
const int MAXN = 2e3 + 10;
int n,m;
string s,ss;
map<char,int> a,d;
int dp[MAXN][MAXN];
int main() {
    mem(dp,0);
    cin>>m>>n;
    cin>>s;
    for(int i=0;i<m;i++){
        cin>>ss;
        cin>>a[ss[0]]>>d[ss[0]];
    }
    for(int len=1;len<=n;len++){
        for(int i=0;i+len<n;i++){
            int j=i+len;
            if(s[i]==s[j]){
                dp[i][j]=dp[i+1][j-1];
            }
            else {
                int ans1=dp[i+1][j]+min(a[s[i]],d[s[i]]);
                int ans2=dp[i][j-1]+min(a[s[j]],d[s[j]]);
                dp[i][j]=min(ans1,ans2);
            }
        }
    }
    cout<<dp[0][n-1]<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/joovo/article/details/79370234