poj 3280

给你长度为m的字符串,其中有n种字符,每种字符都有两个值,分别是插入这个字符的代价,删除这个字符的代价,让你求将原先给出的那串字符变成一个回文串的最小代价。

题目是说(1 ≤ M ≤ 2,000),所以大概是O(n^2)的算法,那就可以考虑二维的算法去解决,由于bcb的最优策略和abc的最优策略可以决定abcb的最优策略,所以考虑区间dp

  1. 定义dp[i][j]为i到j的区间的最优解,
  2. 要么dp[i][j] 是dp[i+1][j]在后面加一个str[i]或者把前面的str[i]去掉。
  3. 要么dp[i][j] 是dp[i][j-1]在前面加一个str[j]或者把后面的str[j]去掉。

由于dp[i][j]依赖于dp[i+1][j]和dp[i][j-1],所以i应该从大到小历遍,j应该从小到大历遍。

  1. 对于i<j,dp[i][j]应该默认是INF(所有情况默认不可到达)
  2. 对于i==j,dp[i][j]应该默认为0(只有一个符号的情况代价为0)
  3. 对于i>j,dp[i][j]应该默认为0(如第5位到第3位,需要的代价为0)
    所以代码应该这样写

总结dp一般有四个关键点

  1. 状态定义
  2. 状态转移
  3. 循环顺序
  4. dp数组的默认值
#include <iostream>
#include <cstdio>
#include <iomanip>
#include <string>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <set>
#include <vector>
#include <map>
#include <algorithm>
#include <cmath>
#include <stack>
#include <stdlib.h>
#include <stdio.h>

#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f3f3f3f3f
#define ll long long
#define ull unsigned long long
#define uint unsigned int
#define l(x) (x<<1)
#define r(x) (x<<1|1)
#define ms(a,b) memset(a,b,sizeof(a))

using namespace std;

int n, m,  a, b;
int in[27], de[27], dp[2222][2222];
char str[2222],c;

int main() {
	ios::sync_with_stdio(false);
	cin >> n >> m;
	cin >> str;
	for (int i = 0; i < n; i++) {
		getchar();
		cin >> c >> a >> b;
		in[c - 'a'] = a;
		de[c - 'a'] = b;
	}

	for (int i = m - 1; i >= 0; i--) {
		dp[i][i] = 0;
		for (int j = i + 1; j < m; j++) {
			dp[i][j] = INF;
			if (str[i] == str[j]) dp[i][j] = dp[i + 1][j - 1];
			
			dp[i][j] = min(dp[i][j], min(dp[i + 1][j] + in[str[i] - 'a'], dp[i + 1][j] + de[str[i] - 'a']));
			dp[i][j] = min(dp[i][j], min(dp[i][j - 1] + in[str[j] - 'a'], dp[i][j - 1] + de[str[j] - 'a']));
		}
	}

	cout << dp[0][m - 1] << endl;

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值