动态规划专题练习题解

本文是一篇关于动态规划的专题练习,包括数字三角形问题的解决方案,探讨了如何找到数字金字塔中路径和的最大值,以及解决合唱队形问题,通过求解最长不下降子序列确定最少需要出列的同学数量。文章适合熟悉动态规划基础的读者进阶学习。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

DP练习

前言

注意:这些DP过于简单,除非小白尽量不要看~
自己写也可以写出来!!!

数字三角形

题目描述

考虑在下面被显示的数字金字塔。
写一个程序来计算从最高点开始在底部任意处结束的路径经过数字的和的最大。
每一步可以走到左下方的点也可以到达右下方的点。

7
3 8
8 1 0
2 7 4 4
4 5 2 6 5

在上面的样例中,从7 到 3 到 8 到 7 到 5 的路径产生了最大和:30

思路

每个点DP一次,找从上面两个点中产生的最大值。

代码

#include <cstdio>
using namespace std;
int n,a[1005][1005],i,j,ans,f[1005][1005],k;
int max(int x,int y)
{
	if(x>y) return x;
	else return y;
}
int main()
{
	freopen("numtri.in","r",stdin);
	freopen("numtri.out","w",stdout);
	scanf("%d",&n);
	for(i=1;i<=n;i++) for(j=1;j<=i;j++) scanf("%d",&a[i][j]);
	f[1][1]=a[1][1];
	for(i=1;i<=n;i++) for(j=1;j<=i;j++)
	{
		f[i][j]=max(f[i-1][j],f[i-1][j-1])+a[i][j];
		
	}
	for(i=1;i<=n;i++) ans=max(ans,f[n][i]);
	printf("%d",ans);
}

背包问题

详见背包问题专题练习

合唱队型

题目描述

N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形。

合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2…,K,他们的身高分别为T1,T2,…,TK, 则他们的身高满足T1<…Ti+1>…>TK(1<=i<=K)。

你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。

思路

两边分别DP求最长不下降子序列。

代码

#include<bits/stdc++.h>
using namespace std;
int a[500],b[500],c[500],i,j,n,m;
int main()
{
	freopen("chorus.in","r",stdin);
	freopen("chorus.out","w",stdout);
	scanf("%d",&n);
	for(i=1; i<=n; i++) scanf("%d",&a[i]);
	for(i=1; i<=n; i++)
	{
		c[i]=1; 
		for(j=1; j<=i-1; j++) if((a[j]<a[i])&&(c[j]+1>c[i])) c[i]=c[j]+1;
    }	
	for(i=n; i>=1; i--)
	{
		b[i]=1; 
		for(j=i+1; j<=n; j++) if((a[j]<a[i])&&(b[j]+1>b[i])) b[i]=b[j]+1;
    }	
	for(i=1; i<=n; i++)	
	if(c[i]+b[i]>m) m=c[i]+b[i];
	printf("%d",n-m+1);
}

前言

题目描述

设有由n个不相同的整数组成的数列,记为:b(1)、b(2)、……、b(n)且b(i)<>b(j) (i<>j),若存在i1<i2<i3< … < ie 且有b(i1)<b(i2)< … <b(ie)则称为长度为e的不下降序列。程序要求,当原数列出之后,求出最长的不下降序列。
例如13,7,9,16,38,24,37,18,44,19,21,22,63,15。例中13,16,18,19,21,22,63就是一个长度为7的不下降序列,同时也有7 ,9,16,18,19,21,22,63长度为8的不下降序列。

思路

过于简单,详见代码。

代码

#include<cstdio>
int n,a[10001],b[10001],maxx;
int max(int x,int y)
{
	return x>y?x:y;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;++i)
	{
		scanf("%d",&a[i]);
		b[i]=1;
	}
	for(int i=n-1;i>=1;--i)
	{
		for(int j=i+1;j<=n;++j)
		{
			if(a[i]<=a[j])
			{
				b[i]=max(b[i],b[j]+1);
			}
		}
	}
	for(int i=1;i<=n;++i)
	{
		maxx=max(b[i],maxx);
	}
	printf("%d",maxx);
	return 0;
}

后记

这些题目非常简单,同学们只要会DP,多练习就可以做出来。感谢大家的支持!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值