(POJ3280)Cheapest Palindrome(区间DP)

题目链接:3280 -- Cheapest Palindrome

题意: 给你一个字符串,然后给你每个字母添加或者删除所需要的代价,问你把原序列变成回文串的最小代价是多少?

输入:第一行给出序列中含有的不同字母n和序列长度l

接下来一行给出序列

接下来n行分别给出每个字母添加或者删除所需要的最小代价

分析:这是一道用区间DP来解决的题目,设f[i][j]表示将原序列中第i个字符到第j个字符变为回文序列的最小代价,那显然有f[i][i]=0,因为单个字符也算是回文串,关键是来看一下怎么进行动态转移

分两种情况进行讨论:

(1)s[i]==s[j],那么就有f[i][j]=f[i+1][j-1],因为第i个和第j个字符相等就意味着把序列第i~j变成回文串只需要把i+1~j-1变成回文串即可,所需代价是相同的。

(2)s[i]!=s[j],这个时候我们又需要进行分类讨论,我们可以知道的是这时候i~j一定不是回文序列,为了使其变成回文序列,我们有以下几种做法:要么在第j个字符后面添加一个与第i个字符相同的字符,或者直接删除第i个字符,或者在i前面添加一个与第j个字符相同的字符,再或者直接删除第j个字符,我们一个一个进行分析

1.在第j个字符后面添加一个与第i个字符相同的字符,那么这个时候f[i][j]=f[i+1][j]+添加第i个字符的代价,这个时候我们就默认第i+1~j个字符已经是回文串了

2.直接删除第i个字符,那么这个时候f[i][j]=f[i+1][j]+删除第i个字符的代价,这个时候我们也是默认第i+1~j个字符已经是回文串了

3.在i前面添加一个与第j个字符相同的字符,这个时候f[i][j]=f[i][j-1]+添加第j个字符的代价,这种情况是默认第i~j-1个字符是回文串

4.直接删除第j个字符,这个时候f[i][j]=f[i][j-1]+删除第j个字符的代价,这种情况也是默认第i~j-1个字符是回文串

我们只需要对上述几种情况取一个最小值即可,我们发现情况1和2都是利用的f[i+1][j],不同点仅在于是添加第i个字符还是删除第i个字符,所以我们可以直接在读入时存下修改第i个字符的最小代价,也就是在添加和删除之间取一个最小值,情况3和4同理

下面说一下初始化:由于是求最小值,所以肯定要把所有的f[i][j]初始化为正无穷大,然后再对一些特殊值进行修改,比如f[i][i]=0,f[i][i-1]=0,f[i][i]等于0很好理解,因为单个字符就是回文串,根本不需要修改,所以代价为0,但是f[i][i-1]等于0该如何理解呢?其实不难发现这是一种无效字符,也就是说他只在一开始的答案更新中起作用,换句话说就是他只在长度为2的区间更新中起作用,这是由转移方程决定的,因为当s[i]==s[j]时有f[i][j]=f[i+1][j-1],若j=i+1,那么f[i][j]=f[i+1][i],实际上这个应该等于0,所以我们只需要把f[i][i-1]初始化为0即可

下面是代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<cmath>
#include<queue>
using namespace std;
const int N=2e3+10;
int f[N][N];//f[i][j]代表将原序列中第i个字符到第j个字符变为回文序列的最小代价 
int mp[N];//mp[a]代表删除a和添加a所需代价的较小值 
int main()
{
	int n,l;
	cin>>n>>l;
	string s;
	cin>>s;
	s=" "+s;//让s的有效字符从1开始 
	memset(f,0x3f,sizeof f);
	char op[5];
	for(int i=1;i<=n;i++)
	{
		scanf("%s",op);
		int x,y;
		scanf("%d%d",&x,&y);
		mp[op[0]]=min(x,y);
	}
	for(int i=1;i<=l;i++) 
		f[i][i-1]=f[i][i]=0;//无效字符串和单个字符的代价都是0
	for(int len=2;len<=l;len++)
	for(int i=1;i+len-1<=l;i++)
	{
		int j=i+len-1;
		if(s[i]==s[j]) f[i][j]=f[i+1][j-1];
		f[i][j]=min(f[i][j],f[i+1][j]+mp[s[i]]);
		f[i][j]=min(f[i][j],f[i][j-1]+mp[s[j]]);
	}
	cout<<f[1][l];
	return 0;
}

猜你喜欢

转载自blog.csdn.net/AC__dream/article/details/123912327
今日推荐