la 4394 string painter 区间dp

开始练dp了,要好好练啊。

这是一道区间dp的题目,每次对序列的一个区间操作,区间dp有一个特点是,对于某一个区间,如果你没有对这个区间进行操作,而对这个区间的子区间进行操作,那么这个区间就没有必要再操作了,否则对子区间的操作就成了费操作,这个是区间dp的决策,决策是对本区间进行大操作,还是分到其他子区间(o(n))的分法

本题就是这样,dp【i】【j】表示从i到j的原序列变成末序列需要的费用,显然看是否对序列本身操作,然后分到子区间中,这个时候发现对本身进行操作之后,就会变成一个全是同种字母的区间,把他们也加入状态,还是同上的dp,就可以得到答案,不过百度大神有先算白板的,复杂度更低一点

每个字符串,到末状态,如果说修改本身的话,一定是在末状态的头和尾相等的时候修改,否则和分到子区间再分别修改是一样的,这样就又减少了决策时转移的状态数

反正我是A了……好题啊,充分利用了区间dp的性质

#include
#include
#include
#include
#include
using namespace std;
const int maxn = 100;
const int INF = 111111111;
char sa[maxn],sb[maxn];
int d[maxn][maxn][27];
int length;
//一坨到对应的 
int dp(int l,int r,int col)//26表示原串 
{
	int tem;
	if (d[l][r][col] != -1) return d[l][r][col];
	if (l > r) return 0;//只有0个,相等 
	if (l == r) {//只有一个 
	    if (col == 26) d[l][r][col] = (1 - (sa[l] == sb[l]));
	    else d[l][r][col] = (1 - (col == sb[l] - 'a'));
		return d[l][r][col];
    }
	//涂整个 
	if (sb[l] == sb[r]) tem = dp(l + 1,r - 1,sb[l] - 'a') + 1;
	//else tem = min(dp(l + 1,r,sb[l] - 'a'),dp(l , r - 1,sb[r] - 'a')) + 1; 加了这句话会慢几乎一倍,没有深刻分析问题
    //分开 
	for(int i = l + 1; i <= r; i++)
	    tem = min(tem,dp(l,i - 1,col) + dp(i,r,col));
    d[l][r][col] = tem;
    
	return tem;
}
int main()
{
    while(scanf("%s %s",sa,sb) != EOF){
    	length = strlen(sa);
    	memset(d,-1,sizeof(d));
		printf("%d\n",dp(0,length - 1,26));
    }	
	return 0;
} 

你可能感兴趣的:(la 4394 string painter 区间dp)