dp——P1049 装箱问题(滚动数组)

一、 题目描述

1、题目描述

  • 有一个箱子容量为V(正整数,0≤V≤20000),同时有nn个物品(0

2、输入格式

1个整数,表示箱子容量。
1个整数,表示有n个物品。
接下来n行,分别表示这n个物品的各自体积。

3、输出格式

1个整数,表示箱子剩余空间。

4、输入输出样例

样例输入

24
6
8
3
12
7
9
7

样例输出

0

二、解题思路

这一道题是一个明显的01背包 ,如果把这个箱子的体积当作重量,把这个箱子的体积当作价值的话,这道题的意思就是求解当总体积不超过m的书当中,体积(价值)最大的就是最优解,很显然,这是一道多阶段决策最优化问题。

1、数学建模

令dpi,j代表前i个货物,假如用背包容量为j的背包来装最多能装多少价值(体积)。

2、状态转移方程

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

具体的原因,就不用再讲了吧……

3、边界(初始化)

dpi,0=dp0,j=0;
如果是全局变量就不用单独赋值了。

三、空间优化(滚动数组)

因为前面讲的太简单了,所以来讲稍微难一点点的,其实也不难

1、想法

这个想法是从列表开始的……

样例输入

8
6
1 
3
4
5
6
10

样例输出

0

根据样例列表格

dp数组 1 2 3 4 5 6 7 8
1 0 0 0 0 0 6 6 6
2 1 1 1 1 1 6 7 7
3 1 1 3 4 4 6 7 7
4 1 1 3 4 5 6 7 8
5 1 1 3 4 5 6 7 8
6 1 1 3 4 5 6 7 8

ans=m-dp6,8=8-dp6,8=0

2、思考

我们考虑dp4,5,它的取值和dp3,5和dp3,1有关,根据状态转移方程可以很开的得出,dp4,5=dp3,1+4=5,我们会发现,dpi,j的取值只与第i-1行有关,依此类体。第1行与第0行有关,第2行与第1行有关,第3行与第2行有关……所以我们会发现想要得到取值,只需要两行就满足了。

3、结论

dp数组 1 2 3 …… k-1 k k+1 …… n-1 n
1 a b c d e f g h i j
2 k l m n o p q r s t

那能不能再优化呢?答案是肯定的,因为如上表计算p时,只要依赖f和a或b或c或d或e。那么我们可以将计算的结果直接更改,例如计算完p时就可以直接把f更新,但是要注意的是这时的循环顺序就要改变了,因为f的值可能会影响到q、r、s、t的值,所以要采用从n到1的枚举方法,这样就不会有所影响了。

四、代码

1、普通代码

#include 
#include 
using namespace std; 
int m,n; 
int w[20010],dp[20010][20010],v[20010]; 
void init()
{
	scanf("%d%d",&m,&n);     
	for(int i=1;i<=n;i++)          
	{
		scanf("%d",&w[i]);
		v[i]=w[i];
	}
}
void work()
{
	for(int i=1;i<=n;i++)          
		for(int j=1;j<=m;j++)                
			if(j>=w[i])                      
				dp[i][j]=max(dp[i-1][j-w[i]]+w[i],dp[i-1][j]); 
			else
				dp[i][j]=dp[i-1][j];
	printf("%d",m-dp[n][m]);
}
int main() 
{     
	init();
	work();
	return 0; 
}  

2、滚动数组代码

#include 
#include 
using namespace std; 
int m,n; 
int w[20010],dp[20010],v[20010]; 
void init()
{
	scanf("%d%d",&m,&n);     
	for(int i=1;i<=n;i++)          
	{
		scanf("%d",&w[i]);
		v[i]=w[i];
	}
}
void work()
{
	for(int i=1;i<=n;i++)          
		for(int j=m;j>=1;j--)                
			if(j>=w[i])                      
				dp[j]=max(dp[j-w[i]]+w[i],dp[j]); 
			else
				dp[j]=dp[j];
	printf("%d",m-dp[m]);
}
int main() 
{     
	init();
	work();
	return 0; 
}  

你可能感兴趣的:(动态规划,动态规划,c++)