DP题目讲解

1,题目详见:http://www.51nod.com/Challenge/Problem.html#!#problemId=1055

解析:要是个等差数列,所以要排序,让后以i为第一项,j为第二项的最长等差数列

那么第三项则为f[i][j]=f[j][k]+1;

可是这样是三重循环,但是这满足这样一个等式:a[k]-a[j]=a[j][i];

所以我么只要枚举j,让后i,k分别向左右枚举时间复杂度就为O(n*n)了

但是这样还会卡时间,所以用short int来设置

但是还要用long long,也会爆,所以还要有滚动数组来优化空间

代码如下:

#include<bits/stdc++.h>
using namespace std;
int read()
{
	int num=0;bool flag=1;
	char c=getchar();
	for(;c<'0'||c>'9';c=getchar())
	  if(c=='-')flag=0;
	for(;c>='0'&&c<='9';c=getchar())
	  num=(num<<1)+(num<<3)+c-'0';
	return flag?num:-num;
}
const int N=10001;
int a[N],n;
short int f[N][N];
int main()
{
	n=read();
	for(int i=1;i<=n;i++)
	  a[i]=read();
	sort(a+1,a+n+1);
	for(int i=1;i<=n;i++)
	  for(int j=i+1;j<=n;j++)
	    f[i][j]=2;
	for(int j=n;j>=1;j--)
	{
		int i=j,k=j;
		for(;i>=1&&k<=n;)
		if(a[j]-a[i]==a[k]-a[j])
		  f[i][j]=f[j][k]+1,i--,k++;
		else if(a[j]-a[i]<a[k]-a[j])i--;
		else k++;
	}
	short int maxx=0;
	for(int i=1;i<=n;i++)
	  for(int j=i+1;j<=n;j++)
	    maxx=max(maxx,f[i][j]);
	cout<<maxx;
	return 0;
}

2,题目详见:http://www.51nod.com/Challenge/Problem.html#!#problemId=1052

解析:

动态规划,借助矩阵可以直观的看到计算过程。

定义二维数组dp, dp[ i ][ j ],表示前 j 项所构成 i 子段的最大和,且必须包含着第j项,即以第j项结尾 然后是一个递推过程。

求dp[ i ][ j ],有两种情况

1、dp[ i ][ j ] = dp[ i ] [ j-1 ] + a[ j ] ,即把第j项融合到第 j-1 项的子段中,子段数没变

2、dp[ i ][ j ] = max(dp[ i-1 ] [ t ]) + a[ j ],(i-1<= t < j ) 把第 j 项作为单独的一个子段,然后找一下i-1个子段时,最大的和,然后加上a[ j ] F[m][m]—f[m][n]

这题同样也可以用滚动数组。

代码如下:

#include<bits/stdc++.h>
using namespace std;
const int NN=5001;
const int N=2;
long long f[NN][2],a[NN],b[NN],n,m,ans;
int main()
{
	read(n);read(m);int num=0,ans1=0;
	int x,p=1;read(x);
	while(x<0){p++;read(x);}
	for(int i=p;i<n;i++)
	{
	  if(x)
	  {
	  	if(x*a[num]>0)a[num]+=x;
	  	  else a[++num]=x;
	  }
	  read(x);
	}
	if(x)
	  {
	  	if(x*a[num]>0)a[num]+=x;
	  	  else a[++num]=x;
	  }
	if(a[num]<0)num--;
	n=num;
	for(int i=1;i<=n;i++)
	  if(a[i]>0)ans1+=a[i];
	if(m>=n){cout<<ans1;return 0;}
	for(int j=1;j<=m;j++)
	 {
	   for(int i=j-1;i<=n;i++)
	    {
	      f[i][j%N]=max(f[i-1][j%N]+a[i],b[i-1]+a[i]);
	      if(j==m&&i>m)ans=max(ans,f[i][j%N]);
	    }
	   for(int k=j+1;k<=n;k++)b[k]=max(b[k-1],f[k-1][j%N]);
	 }
	printf("%lld",ans);
	return 0;
}

这题的更高的算法便是贪心,因为这是DP讲解所以不说了

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值