动态规划知识总结

本文介绍了动态规划的基本思想和使用条件,强调了最优子结构和重叠子问题的重要性。通过0-1背包问题为例,展示了如何利用动态规划自底向上计算最优解,并给出了解决该问题的C++代码实现。动态规划通过存储子问题的解避免重复计算,提高效率,适用于物品选择、任务调度等优化问题。

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

  • 基本思想:问题的最优解如果可以由子问题的最优解推导得到,则可以先求解子问题的最优解,再通过子问题的解构造原问题的最优解;若子问题有较多的重复出现,则可以自底向上从最终子问题向原问题逐步求解。
  • 使用条件:原问题无后效性,具有有最优子结构和重叠子问题
    • 最优子结构:
      • 一个问题的优化解包含了子问题的优化解
      • 缩小子问题集合,只需那些优化问题中包含的子问题,降低实现复杂性
    • 重叠子问题:在问题的求解过程中,很多子问题的解将被多次使用。
  • 算法的设计步骤:
    • 找出最优解的性质,并刻画其结构特征
    • 递归地定义最优值
    • 以自底向上地方式计算最优值
    • 根据计算最优值得到的信息,构造最优解
  • 特点:
    • 把原始问题划分成一系列子问题;
    • 每个子问题仅求解一次,并将结果保存在表中,以后用到时直接存取,不重复计算,节省计算时间
    • 自底向上地计算。
    • 整体问题最优解取决于子问题的最优解(状态转移方程)
  • 本章共学习例题有
  • 1.矩阵连乘问题
  • 2.最长公共子序列
  • 3.最大字段和
  • 4.凸多边形最优三角剖分
  • 5.多边形游戏
  • 6.图像压缩
  • 7.0-1背包问题
  • 8.最优二叉搜索树
  • 9.独立任务最优调度问题
  • 10.最优批处理问题
  • 11.石子合并问题
  • 12.数字三角形问题
  • 13.租用游艇问题
  • 14.最小m段和问题

例题:0-1背包问题

问题描述:

   给定n种物品和一背包。物品i的重量是wi,其价值为vi,背包的容量为C。问应如何选择装入背包的物品,使得装入背包中物品的总价值最大?

本题存在约束条件

 即,要找到一个物品的组合,使得它们的重量小于等于最大容量,并且其价值最大。

设所给0-1背包问题的子问题的最优值为m[i][j], m[i][j]的含义是是在背包容量为j,可选物品为1—— i 时的0-1背包问题的最优值。由0-1背包问题的最优子结构性质,可建立计算m[i][j]的递归式如下:

 即在背包容量允许的情况下如果不放入第 i 件物品,则问题转换为“前i - 1件物品放入容量为 j 的背包中”;如果放入第 i 件物品,则问题转化为“前i - 1件物品放入容量为 j - w[i] 的背包中”,此时的最大值为 max{m[i - 1][j], m[i - 1][j - w[i]] + v[i] };若背包容量不足,则只能转换为“前i - 1件物品放入容量为 j 的背包中”。

 这个时候我们就要定义一个表格m[n][w]。这个表的意义为:当我到拿第 i件物品的阶段时,当前的剩余容量 j下的最大价值。我们要根据递推式从表格的左上角开始,一直推理到表格的右下角,即当我到拿完所有物品的时,当前的剩余容量 w下的最大价值

 

#include<iostream>
#include<stdlib.h>
#include<fstream> 
using namespace std;
class mystrious_ranch
{
	private:
	 int n,w;
	 int *val,*wei,**m,*p;
	 ifstream in;
	 ofstream out;
	 void fopen()
	 {
	 	in.open("input.txt"); 
	 	out.open("output.txt"); 
	 }
	 void read()
	 {
	 	in>>n>>w;
	 	if(n<1||w<1)
	 	{
	 		cout<<"物品的数量或背包的承重量不合理"<<endl;
	 		exit(0);
		}
	 	val=new int[n+1];
	 	wei=new int[n+1];
	 	int i;
	 	for(i=1;i<n+1;i++)
	 	{
	 		in>>val[i];
	 		if(val[i]<1)
	 		{
	 			cout<<"物品的价值不合理"<<endl;
	 			exit(0);
			}
		}
	 	for(i=1;i<n+1;i++)
	 	{
	 		in>>wei[i];
	 		if(wei[i]<1)
	 		{
	 			cout<<"物品的重量不合理"<<endl;
	 			exit(0);
			}
		}
	 	m=new int*[n+1];
	 	for(i=0;i<n+1;i++)
	 	 m[i]=new int[w+1];
	 	p=new int[n+1];
	 	for(i=0;i<n+1;i++)
	 	 m[i][0]=0;
	 	for(i=0;i<w+1;i++)
	 	 m[0][i]=0;
	 }
	 void output()
	 {
	 	out<<m[n][w]<<endl;
	 	int i,j;
	 	i=n,j=w;
	 	/*从i=n,j=w开始寻找,如果ks(i-1,j)=ks(i,j),说明第i个物品没有被选中,从ks(i-1,j)继续寻找。
		 否则,表示第i个物品已被选中,则从ks(i-1,j-wi)开始寻找。*/
	 	while(1)
	 	{
	 		if(m[i][j]==m[i-1][j-1])//第i个没被选上
	 		 p[i]=0;
			else
			{
				p[i]=1;
				j-=wei[i];
			} 
			i--;
			if(i==0)
			 break;
		}
	 	for(i=1;i<n+1;i++)
	 	 out<<p[i]<<" ";
	 }
	public:
	 void loot()
	 {
	 	fopen();
	 	read();
	 	int i,j;
	 	for(i=1;i<n+1;i++)
	 	{
	 		for(j=1;j<w+1;j++)
	 		{
	 			if(wei[i]>j)
	 			 m[i][j]=m[i-1][j];
	 			else
	 			 m[i][j]=max(m[i-1][j],m[i-1][j-wei[i]]+val[i]);
			}
		}
	 	output();
	 }
	 ~mystrious_ranch()
	 {
	 	delete[]m;
	 	delete[]p;
	 	in.close();
	 	out.close();
	 }
}; 
int main()
{
	mystrious_ranch mr;
	mr.loot();
	return 0;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值