POJ3624–01背包
一、题目描述
Description
Bessie has gone to the mall’s jewelry store and spies a charm bracelet. Of course, she’d like to fill it with the best charms possible from the N (1 ≤ N ≤ 3,402) available charms. Each charm i in the supplied list has a weight Wi (1 ≤ Wi ≤ 400), a ‘desirability’ factor Di (1 ≤ Di ≤ 100), and can be used at most once. Bessie can only support a charm bracelet whose weight is no more than M (1 ≤ M ≤ 12,880).
Given that weight limit as a constraint and a list of the charms with their weights and desirability rating, deduce the maximum possible sum of ratings.
Input
- Line 1: Two space-separated integers: N and M
- Lines 2…N+1: Line i+1 describes charm i with two space-separated integers: Wi and Di
Output - Line 1: A single integer that is the greatest sum of charm desirabilities that can be achieved given the weight constraints
Sample Input
4 6
1 4
2 6
3 12
2 7
Sample Output
23
二、解题思路
01背包。在这道题输入的数据有物品种类n、背包容量m、每个物品的容量v[i]、每个物品的价值d[i]。然后双层for循环实现操作,过程其实我也描述不太清楚,我就大概说一下,然后理解模板中的代码,之后参考模板多做题就可以自己写了。先拿第一个物品v=1,d=4,装进背包,那么背包里边的情况就是容量剩余5,价值是4(dp[1]=dp[2]=dp[3]=dp[4]=dp[5]=dp[6]=4),再装入第二个物品v=2,d=6,那么背包里边的情况就是容量剩余3,价值是10,(注意:这里再循环里边计算的时候在dp数组中是加了一种情况的,当背包中只有第二件物品时,背包容量剩余4,价值6,容量比之前大,这时刷新了之前dp[2]的值)经过这一轮刷新后结果为(dp[1]=4,dp[2]=6,dp[3]=dp[4]=dp[5]=dp[6]=10),依此类推。可见用语言描述这个过程是很复杂的,需要我们自己把这个背包容量变化的过程给理解透彻,只有这样我们才能够学会这个知识点。(个人建议把这个背包容量变化的过程通过循环输出出来,然后根据数据的变化去理解这个知识,我在参考代码里边把这个打印的代码给注释了,需要的同学可以用一下。)
三、参考代码
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
#define INT_MAX 1 << 30
#define MAX 100
typedef long long ll;
int n,m;
int v[3500];
int d[3500];
int dp[20000];
int f[3000][3000];
int main()
{
memset(dp,0,sizeof(dp));
scanf("%d%d",&n,&m);
for (int i = 1; i <=n; i += 1)
{
scanf("%d%d",&v[i],&d[i]);
}
for (int i = 1; i <=n; i++)
{
for (int j = m; j >= v[i]; j--)
{
dp[j] = max(dp[j],dp[j-v[i]]+d[i]);
}
}
/*for (int i = 1; i <=m; i++)
{//这里其实就是最终的变化结果,想要看过程的可以看下边注释里边那个二维数组的打印过程。
cout<<dp[i]<<' ';
}*/
printf("%d\n",dp[m]);
/*memset(f, 0, sizeof f);
for (int i = 1; i <= n; i++)
{
for (int j = 1; j < v[i]; j++)
f[i][j] = f[i - 1][j];
for(int j = v[i]; j <= m; j++)
{
if (f[i - 1][j] < f[i - 1][j - v[i]] + d[i])
f[i][j] = f[i - 1][j - v[i]] + d[i];
else
f[i][j] = f[i - 1][j];
}
}
for(int i=1; i<=n; i++)
{//背包容量的变化过程
for(int j=1; j<=m; j++)
{
cout<<f[i][j]<<' ';
}
cout<<endl;
}
cout << f[n][m] << "\n";*/
return 0;
}
四、总结
刚开始学01背包的时候并不容易,动态规划本来就是比较抽象的知识,因为我们很难看透数据的变化,就像我们最开始学习递归的时候,就现在一些递归我还是不太理解的,可见我们需要不断地学习这些知识,当我们做题多了,思维开发的多了,这些知识自然而然地就理解了。