动态规划:线性dp、背包问题、区间3

区间DP

2955 -- Brackets

给定一个由字符 a1a2 ... an 组成的括号序列,你的目标是找到最长的正则括号序列的长度,它是 s 的子序列。也就是说,您希望找到最大的 m,使得对于索引 i1、i2、...、im,其中 1 ≤ i1 < i2 < ... < im ≤ n,ai1ai2 ... aim 是常规括号序列。

接下来就是强行把自己讲懂的……QAQ

子状态:我们想,既然最后要求的是从0到len-1的区间中有多少个括号被匹配,那这个答案是怎么推过来的呢?肯定是从它的前面推过来的,也就是0到len-2等等,那就设子状态为f[i][j],其中i表示起始位置,j表示终止位置。

转移方程:每一个区间都是它由括号划分成的  两段子区间之和  中的最大值,                         即 f[i][j]=max(f[i][j],f[i+1][k-1]+f[k+1][j]+2),如果没有匹配的括号,说明可以略过第一个括号,     即f[i][j]=f[i+1][j]。

边界条件:若i>=j,则f[i][j]=0。当f[i][j]有值就直接返回,所以初始值应当设为-1。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
//scanf("",&);
const int inf = 0x3f3f3f, maxn=105;
string s;
int f[maxn][maxn];
int calc(int i,int j){
	if(f[i][j]!=-1)
		return f[i][j];
	if(i>=j)
		return f[i][j]=0;
	f[i][j]=calc(i+1,j);
	for(int k=i+1;k<=j;++k)//
		if((s[i]=='('&&s[k]==')')||(s[i]=='['&&s[k]==']'))
			f[i][j]=max(f[i][j],calc(i+1,k-1)+calc(k+1,j)+2);
	return f[i][j];
}
int main(){
	while(cin>>s){
		if(s=="end") break;
		memset(f,-1,sizeof(f));
		int len=s.length();
		calc(0,len-1);
		cout<<f[0][len-1]<<endl;
	}
	return 0;
}

最长回文子序列长度

给你一个长度为n的序列,求最长回文子序列长度(子序列可不连续)。

法一:线性dp。可以求原串和其倒序串的最长公共子序列。

法二:区间dp。f[i][j]表示ij之间的最长回文子序列,则若ai与aj相同,f[i][j]=f[i+1][j-1]+2,否则          f[i][j]=max(f[i+1][j], f[i][j-1]),即分别求去掉头尾的最长回文子序列。

拓展:最长回文子串长度(子串必须连续)

既然一个串的子串只要有一个不满足回文就无法再扩展回文长度,那么我们可以直接设置bool数组,f[i][j]表示从i到j是否为回文串,则f[i][j]=f[i+1][j-1]&&(a[i]==a[j])。答案用ans=max(ans,j-i+1)维护即可。更优的办法:manacher。

链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网
 

石子合并

将n堆石子绕圆形操场排放,

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值