您的位置:首页 > Web前端 > JavaScript

区间DP(记搜)——BZOJ1032/Luogu2145 [JSOI2007]祖码Zuma

2017-05-23 20:01 274 查看
题面:BZOJ1032 Luogu2145

一个很明显的区间DP

首先预处理,把相同颜色的连续珠子全部搞到一个数组段里去

v记录该段的数值,w记录该段的长度

定义状态:f[i][j]表示区间从i段j段全部消掉所需最少珠子数

然后一个最显然最基础的状态转移方程:

f[i][j]=min(f[i][j],f[i][k]+f[k+1][j])

这是区间DP几乎必有的转移方程了吧,k从i到j-1枚举

然后就是边界条件和特殊处理的东西了

如果i=j,那么f[i][j]就是这一段要消掉的珠子数啦,题中有讲原来连三颗以上的珠子还需要一颗来激活,所以如果w>=3,f[i][j]=1,否则f[i][j]=2(加2颗凑到3颗)

然后还有一种情况,如果左端点颜色等于右端点颜色,那么f[i][j]=min(f[i][j],f[i+1][j-1]+(两边个数加起来个数是否大于2,是就不用加,不是就+1)

为什么呢,因为保证左右加起来个数肯定大于等于2

然后就可以DP了

这里给上记忆化搜索的代码,因为我感觉记忆化搜索比循环好理解。。。

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<iostream>
#include<cstdlib>
#include<queue>
#include<string>
#include<ctime>
#include<climits>
using namespace std;
int f[501][501];
int n,m=0,a[1001];
int v[1001],w[1001];
inline int dfs(int l,int r){
if(f[l][r])return f[l][r];
if(l==r)return f[l][r]=w[l]>1?1:2;
f[l][r]=1e9;
if(v[l]==v[r]){
if(l+1==r)f[l][r]=1;
else f[l][r]=dfs(l+1,r-1)+(w[l]+w[r]>2?0:1);
}
for(int i=l;i<r;i++)f[l][r]=min(f[l][r],dfs(l,i)+dfs(i+1,r));
return f[l][r];
}
int main()
{
scanf("%d",&n);a[0]=-1;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
if(a[i]==a[i-1])w[m]++;
else v[++m]=a[i],w[m]=1;
}
printf("%d",dfs(1,m));
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  区间dp