动态规划的初次接触,简单分析

一、简单的0,1背包问题

1、题目描述:有n个重量和价值分别为Wi,Vi的物品。从这些物品中挑选出总重量不超过W的物品,求所选方案中价值总和的最大值(注:在0,1背包问题中,每个物品只有一件,可以选择房或者不放)。

【分析】:对于这样的问题,首先我们可以用最简单容易想到的方法,将所有可能一一例举出来,找到最合适的。

对于函数rec(int i,int j)// 这里的 i 表示的是第几个物品,而 j 表示此时背包的容量。

既然是最朴素,简单的想法,那我们就去想一想当前的这件物品我们是否要把它放入背包之中。1、如果不放入背包,我们便直接考虑下一个物品,即:rec(  i+1, j)// 此时i + 1表示下一个物品,背包的容量没有改变,仍然为j;2、如果当前的物品我们加入背包了,即:rec( i+1,j - w[ i ])+v[ i ]   // 此时才能表示这个我们所得得价值。

详见代码:

#include<iostream>
using namespace std;
// n表示物品的个数,W表示背包的容量
int n,W;
// 数组w表示各个物品的容量,数组v表示各个物品的价值
int w[100],v[100];

int rec(int i,int j)
{
	int res;
	// 没有剩余的物品
	if(i == n)
	{
		res = 0;
	//  这个物品不能选择,因为大于背包的容量
	}else if(j < w[i]){
		res = rec(i + 1,j);
	}
	//  挑选或者不挑选这个物品的情况分别尝试
	else{
		res = max(rec(i+1,j),rec(i+1,j-w[i])+v[i]);
	}
	return res;
}

int main()
{
	cin>>n;
	for(int i = 0;i<n;i++)
	{
		cin>>w[i]>>v[i];
	}
	cin>>W;
	cout<<rec(0,W)<<endl;
	return 0;
}

由此,最简单朴素的方法,我们就解决了这个0,1背包问题,但由于上述方法可能浪费了很多的时间,下面一个优化的方法,便由此而来。

试想在上面的搜索中每一层的搜索都有两个分支,最坏需要O(2^n),但其实这些计算结果中有一些我们是已经得到了结果的,而下一次再次搜索时又再次计算,也就是说我们重复的计算了两次,所以我们可以将第一次的计算结果都存储下来,当再次遇到的时候我们可以直接使用。(积累这里的 记忆化搜索!)

详见代码:

#include<iostream>
#include<cstring>
using namespace std;
// n表示物品的个数,W表示背包的容量
int n,W;
// 数组w表示各个物品的容量,数组v表示各个物品的价值
int w[100],v[100];

///在此处加一个“记忆化数组”
int dp[100][100];

int rec(int i,int j)
{
	// 若已经计算过直接使用之前的计算结果
	if(dp[i][j] >= 0)
	{
		return dp[i][j];
	}
	int res;//结果resort
	if(i == n)
	{
		res = 0;
	}else if(j<w[i])
	{
		res = rec(i+1,j);
	}else{
		res = max(rec(i+1,j),rec(i+1,j-w[i])+v[i]);
	}
	// 将结果记录在数组之中。
	return dp[i][j] = res;
}
int main()
{
	cin>>n;
	for(int i = 0;i<n;i++)
	{
		cin>>w[i]>>v[i];
	}
	cin>>W;
	memset(dp,-1,sizeof(dp));
	cout<<rec(0,W)<<endl;
	return 0;
}

到这里,基本形成了动态规划的雏形,但我上述的代码都是用递归去进行的,下面把递归的式子换成使用数组的递推式,也就是我们经常使用的动态规划的递推关系:

dp[ i +1][ j ]  //从前 i 个物品中选出总重量不超过 j 的物品时总价值的最大值。

dp [ 0 ][ j ]  = 0

dp[ i + 1][j] =  max( dp[i][ j ],dp [ i ] [  j - w[i] ] + v[ i ] )

即:

void solve()
{
	for(int i = 0;i<n;i++){
		for(int j = 0;j<= W;j++){
			if(j<w[i]){
				dp[i+1][j] = dp[i][j];
			}else{
				dp[i+1][j] = max(dp[i][j],dp[i][j - w[i]]+v[i]);
			}
		}
	}
	cout<<dp[n][W]<<endl;
}

动态规划的初次接触,简单分析

时间: 2024-12-21 22:15:39

动态规划的初次接触,简单分析的相关文章

c++中类的初次接触

下面是我写的简单的代码,初次接触c++中的类,c++真的是博大精深啊,学习c++的路还很长,加油! 1 /*q1.cpp*/ 2 //一个简单的类极其实例化 3 #include<iostream> 4 using namespace std; 5 6 class Point{ 7 public: 8 //设置坐标 9 void setPoint(int x,int y){ 10 xPos = x; 11 yPos = y; 12 } 13 //打印坐标 14 void printPoint(

[Docker]初次接触

Docker 初次接触 近期看了不少docker介绍性文章,也听了不少公开课,于是今天去官网逛了逛,发现了一个交互式的小教程于是决定跟着学习下. 仅仅是把认为重点的知识记录下来,不是非常系统的学习和笔记. 理论部分 Docker 引擎包括了两个部分,一个守护进程作为server端来管理全部的容器. 一个client.能够远程来控制服务端. Docker有公共的云端仓库 Docker Hub Registry.里面有能够使用的镜像 你能够觉得容器containers就是沙箱box中的一个进程.这个

[转载]通达信插件选股(基于通达信插件编程规范的简单分析)

[转载]通达信插件选股(基于通达信插件编程规范的简单分析) 原文地址:通达信插件选股(基于通达信插件编程规范的简单分析)作者:哈尔滨猫猫 首先声明,鄙人是编程人员,不是股民.对选股概念了解甚少.本文仅作编程人员学习借鉴之用.不对选股理论进行探讨和解释. 以前有客户找我做过通达信插件选股的小任务,当时第一次接触面向接口(此类“接口”)编程,也是第一次接触到股票里相关的概念.最近由于接手一个任务,与上次开发相类似,故旧事重提,仔细研究一番.将个人学习研究所得知识与大家分享.在网上搜相关资料,可用的.

x264源代码简单分析:x264命令行工具(x264.exe)

本文简单分析x264项目中的命令行工具(x264.exe)的源代码.该命令行工具可以调用libx264将YUV格式像素数据编码为H.264码流. 函数调用关系图 X264命令行工具的源代码在x264中的位置如下图所示. 单击查看更清晰的图片 X264命令行工具的源代码的调用关系如下图所示. 单击查看更清晰的图片 从图中可以看出,X264命令行工具调用了libx264的几个API完成了H.264编码工作.使用libx264的API进行编码可以参考<最简单的视频编码器:基于libx264(编码YUV

FFmpeg的H.264解码器源代码简单分析:熵解码(Entropy Decoding)部分

本文分析FFmpeg的H.264解码器的熵解码(Entropy Decoding)部分的源代码.FFmpeg的H.264解码器调用decode_slice()函数完成了解码工作.这些解码工作可以大体上分为3个步骤:熵解码,宏块解码以及环路滤波.本文分析这3个步骤中的第1个步骤. 函数调用关系图 熵解码(Entropy Decoding)部分的源代码在整个H.264解码器中的位置如下图所示. 单击查看更清晰的图片 熵解码(Entropy Decoding)部分的源代码的调用关系如下图所示. 单击查

FFmpeg的H.264解码器源代码简单分析:宏块解码(Decode)部分-帧内宏块(Intra)

本文分析FFmpeg的H.264解码器的宏块解码(Decode)部分的源代码.FFmpeg的H.264解码器调用decode_slice()函数完成了解码工作.这些解码工作可以大体上分为3个步骤:熵解码,宏块解码以及环路滤波.本文分析这3个步骤中的第2个步骤.由于宏块解码部分的内容比较多,因此将本部分内容拆分成两篇文章:一篇文章记录帧内预测宏块(Intra)的宏块解码,另一篇文章记录帧间预测宏块(Inter)的宏块解码. 函数调用关系图 宏块解码(Decode)部分的源代码在整个H.264解码器

FFmpeg的H.264解码器源代码简单分析:解码器主干部分

本文分析FFmpeg的H.264解码器的主干部分."主干部分"是相对于"熵解码"."宏块解码"."环路滤波"这些细节部分而言的.它包含了H.264解码器直到decode_slice()前面的函数调用关系(decode_slice()后面就是H.264解码器的细节部分,主要包含了"熵解码"."宏块解码"."环路滤波"3个部分). 函数调用关系图 解码器主干部分的源代码在

[JS][easyui]jQuery EasyUI Datagrid VirtualScrollView视图简单分析

 大家都知道EasyUI的Datagrid组件在加载大数据量时的优势并不是很明显,相对于其他一些框架,如果数据量达到几千,便会比较慢,特别是在IE下面.针对这种情况,我们首要做的是要相办法优化datagrid组件的各方面性能,不过任何事情都是可以变通解决的,virtualScrollView就是一种不错的解决方案. virtualScrollView的准则就是尽量少画tr到table里,表格的高度是有限的,而用户的可见区域是很有限的,所以数据量很大的时候,是没有必要将所有数据数据都画到表格中

SSIS 初次接触 + 开发记录

第一次接触SSIS,昨天终于把一套流程走通,记一下流水. 1:安装 使用SSIS需要安装插件(VS 和Sql Server都需要另外安装). 自己使用的vs2017开发,官网有专门的 VS2017 安装SSDT的文章,但是自己电脑死活装不上,可能是公司使用了域账户和Symantec杀毒软件的原因. 没有办法,只好重新下载了最新的 VS2019 ,然后在“工具”中使用“获取功能和扩展”安装了SSIS插件,由于自己电脑装不了sql server2017,所以又申请了一台服务器安装Sql Server