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

题面: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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值