钰的动态规划学习笔记

本文介绍了动态规划的基本概念、应用原因以及解决策略。通过实例讲解如何用动态规划解决01背包问题(如P1048采药和P1616疯狂采药),并展示了如何将动态规划应用于背包问题中的两种不同场景。同时,还涵盖了P1434滑雪问题中的最长滑坡求解,通过记忆化搜索实现动态规划。

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

动态规划(dynamic programing)

动态规划是什么?

是运筹学的一个分支,是求解决策过程最优化的数学方法。

为什么要用动态规划?

动态规划利用各个阶段之间的关系,逐个求解,最终求得全局最优解。

怎么用动态规划?

1,确认原问题与子问题

2,动态规划状态

3,边界状态

4,边界状态结值

5,状态转移方程***

由于博主是蒟蒻,所以dp那么多好用的内容要一点点更新,希望本菜鸡坚持更完! 

例题

P1048 采药(01背包模板题)

题目描述

辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”

如果你是辰辰,你能完成这个任务吗?

输入格式

第一行有 22 个整数 TT(1 \le T \le 10001≤T≤1000)和 MM(1 \le M \le 1001≤M≤100),用一个空格隔开,TT 代表总共能够用来采药的时间,MM 代表山洞里的草药的数目。

接下来的 MM 行每行包括两个在 11 到 100100 之间(包括 11 和 100100)的整数,分别表示采摘某株草药的时间和这株草药的价值。

输出格式

输出在规定的时间内可以采到的草药的最大总价值。

输入输出样例

输入 #1复制

70 3
71 100
69 1
1 2

输出 #1复制

3

说明/提示

  • 对于 30\%30% 的数据,M \le 10M≤10;
  • 对于全部的数据,M \le 100M≤100。

NOIP2005 普及组 第三题

原题链接:https://www.luogu.com.cn/problem/P1048

#include<bits/stdc++.h>
using namespace std;
int t,m,dp[1010],w[110],v[110];
int main()
{
	ios::sync_with_stdio(false);
	cin>>t>>m;
	for(int i=1;i<=m;i++) cin>>w[i]>>v[i];
	for(int i=1;i<=m;i++)
	{
		for(int j=t;j>=w[i];j--)//和完全背包的不同 
		dp[j]=max(dp[j-w[i]]+v[i],dp[j]);
	}
	cout<<dp[t];
	return 0;
}

采药的题解有一篇特别良心,博主好像是衡水的?链接:https://nmslqwq.blog.luogu.org/solution-p1048 

 P1616 疯狂的采药(完全背包模板题)

题目描述

LiYuxiang 是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同种类的草药,采每一种都需要一些时间,每一种也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”

如果你是 LiYuxiang,你能完成这个任务吗?

此题和原题的不同点:

11. 每种草药可以无限制地疯狂采摘。

22. 药的种类眼花缭乱,采药时间好长好长啊!师傅等得菊花都谢了!

输入格式

输入第一行有两个整数,分别代表总共能够用来采药的时间 tt 和代表山洞里的草药的数目 mm。

第 22 到第 (m + 1)(m+1) 行,每行两个整数,第 (i + 1)(i+1) 行的整数 a_i, b_iai​,bi​ 分别表示采摘第 ii 种草药的时间和该草药的价值。

输出格式

输出一行,这一行只包含一个整数,表示在规定的时间内,可以采到的草药的最大总价值。

输入输出样例

输入 #1复制

70 3
71 100
69 1
1 2

输出 #1复制

140

说明/提示

数据规模与约定

#include<bits/stdc++.h>
using namespace std;
const int maxm=10010,maxn=10000010;
long long v[maxm],w[maxm],dp[maxn];
int main()
{
	ios::sync_with_stdio(false);
	int t,m;
	cin>>t>>m;
	for(int i=1;i<=m;i++) cin>>w[i]>>v[i];
	for(int i=1;i<=m;i++){
	for(int j=w[i];j<=t;j++)//保证可以重复取,区分01背包 
	dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
	}
	cout<<dp[t];
	return 0;
}

P1434 [SHOI2002]滑雪 

题目描述

Michael 喜欢滑雪。这并不奇怪,因为滑雪的确很刺激。可是为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡或者等待升降机来载你。Michael 想知道在一个区域中最长的滑坡。区域由一个二维数组给出。数组的每个数字代表点的高度。下面是一个例子:

5 5
1   2   3   4   5
16  17  18  19  6
15  24  25  20  7
14  23  22  21  8
13  12  11  10  9

一个人可以从某个点滑向上下左右相邻四个点之一,当且仅当高度会减小。在上面的例子中,一条可行的滑坡为 2424-1717-1616-11(从 2424 开始,在 11 结束)。当然 2525-2424-2323-\ldots…-33-22-11 更长。事实上,这是最长的一条。

输入格式

输入的第一行为表示区域的二维数组的行数 RR 和列数 CC。下面是 RR 行,每行有 CC 个数,代表高度(两个数字之间用 11 个空格间隔)。

输出格式

输出区域中最长滑坡的长度。

输入输出样例

输入 #1复制

5 5
1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9

输出 #1复制

25

说明/提示

对于 100\%100% 的数据,1\leq R,C\leq 1001≤R,C≤100。

原题链接:https://www.luogu.com.cn/problem/P1434

#include<bits/stdc++.h>
using namespace std;
int dx[4]={1,-1,0,0};
int dy[4]={0,0,1,-1};
int n,m,ans;
int a[201][201],s[201][201];
int dfs(int x,int y)
{
	if(s[x][y]) return s[x][y];//记忆化搜索 
	s[x][y]=1;
	for(int i=0;i<4;i++)
	{
		int xx=dx[i]+x;
		int yy=dy[i]+y;// 用于遍历四个方向 
		if(xx>0&&xx<=n&&yy>0&&yy<=m&&a[xx][yy]<a[x][y])//<=n,<=m是因为main里面i,j从1开始 
		{
			dfs(xx,yy);
			s[x][y]=max(s[x][y],s[xx][yy]+1); 
			/*记忆化 疑问:为什么是s[xx][yy]加1?
			解答:相当于向x y点四周遍历,找寻那个最大的s[xx][yy]而这个点是由之前的
			dfs(xx,yy)搜过并且返回了值的,这一步遍历是在比较向四周哪个点滑值更大*/
		}
	}
	return s[x][y];
}
int main()
{
	ios::sync_with_stdio(false);
	cin>>n>>m;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
		cin>>a[i][j];
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
		ans=max(ans,dfs(i,j));//取最大值
	cout<<ans<<endl;
	return 0;	
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值