动态规划:背包问题

Posted 记性不好,多记记吧

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态规划:背包问题相关的知识,希望对你有一定的参考价值。

背包问题  

  • 有一个背包(限定条件:对可选的东西进行限制),从一堆物品中选择若干放进背包,使得最后背包中的价值是最大的
  • 01背包:对于一个物品,可以选0或1    
  • 完全背包:对于一个物品,可以选多次(>=1)  

01背包 

1. 问题描述 http://hihocoder.com/problemset/problem/1038

有M张奖券,奖品区有N件奖品,分别标号为1到N,其中第i件奖品需要need(i)张奖券进行兑换且评分值为value(i)。每件奖品最多只能兑换一次。凭借他手上的M张奖券,可以换到哪些奖品,使得这些奖品的喜好值之和能够最大。

奖品标号 1 ... i ... N
需要奖券 need(1) ... need(i) ... need(N)
评分值 value(1) ... value(i) ... value(N)

2. 状态转换

  • 状态:allValue[i][j] = 喜好总值[当前是第i件物品][前面已经使用的奖券j]
  • 决策:第i件物品是否要选
  • 状态转换: allValue[i][j] = max{allValue[i - 1][j], allValue[i - 1][j - need[i]] + value[i]}
  • 从左往右,从下往上 for(...i...){for(...j...)}

3. 代码

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<stdio.h>
 4 int dp[505][100005];
 5 int w[505],v[505];
 6 int max(int m,int n)
 7 {
 8     return m>n?m:n;
 9 }
10 void solve(int n,int m)
11 {
12     int i,j;
13     for(i=0;i<=m;i++)
14         dp[0][i]=0;
15     for(i=0; i<n; i++)
16         for(j=0; j<=m; j++)
17         {
18             if(j<w[i])
19                 dp[i+1][j]=dp[i][j];
20             else
21                 dp[i+1][j]=max(dp[i][j],dp[i][j-w[i]]+v[i]);
22         }
23         printf("%d",dp[n][m]);
24 }
25 int main()
26 {
27     int n,m,i;
28     scanf("%d%d",&n,&m);
29     for(i=0;i<n;i++)
30             scanf("%d%d",&w[i],&v[i]);
31     solve(n,m);
32     return 0;
33 } 
View Code

完全背包 

1. 问题描述 http://hihocoder.com/problemset/problem/1043

可以兑换无数次

2. 状态转换

  • 状态:allValue[i][j] = 喜好总值[当前是第i件物品][前面已经使用的奖券j]
  • 决策:第i件物品可以选k件(0<=k<=剩余的奖券/第i件物品需要的)
  • 状态转换: allValue[i][j] = max{allValue[i - 1][j - k*need[i]] + k*value[i]}
  • 优化转换关系:
    • 在对j的遍历过程中,会先后计算到allValue[i][j-need[i]], allValue[i][j]
    • 1) allValue[i][j] = max{allValue[i-1][j], allValue[i-1][j-need[i]] + value[i], ...,allValue[i-1][j-k*need[i]]+k*value[i]}
    • 2)allValue[i][j - need[i]] = max{allValue[i-1][j-need[i]] + value[i], ...,allValue[i-1][j-k\'*need[i]]+k\'*value[i]}
    • 1)2)可以转换成:allValue[i][j] = max{allValue[i-1][j], allValue[i][j - need[i]] + value[i]}

3. 代码

 1 #include <iostream>
 2 using namespace std;
 3 const int maxN = 501;
 4 const int maxM = 100001;
 5 int values[maxN][maxM];
 6 struct Prize
 7 {
 8     int need;
 9     int value;
10 }prizes[maxN];
11 
12 
13 void dp(int N, int M)
14 {
15     for (int i = 0; i <= M; i++)
16         if (i >= prizes[0].need)
17             values[0][i] = i / prizes[0].need * prizes[0].value;
18         else
19             values[0][i] = 0;
20     int max = 0;
21     for (int i = 1; i < N; i++)
22     {
23         for (int j = 0; j <= M; j++)
24         {
25             if (prizes[i].need > j)
26                 values[i][j] = values[i - 1][j];
27             else
28             {
29                 int tmp = values[i][j - prizes[i].need] + prizes[i].value;
30                 if (tmp > values[i - 1][j])
31                     values[i][j] = tmp;
32                 else
33                     values[i][j] = values[i - 1][j];
34             }
35         }
36     }
37 }
38 
39 int main()
40 {
41     int M, N;
42     cin >> N >> M;
43     for (int i = 0; i < N; i++)
44         cin >> prizes[i].need >> prizes[i].value;
45     prizes[N].need = prizes[N].value = 0;
46     
47     dp(N, M);    
48     cout << values[N - 1][M] << endl;
49     return 0;
50 }
View Code

以上是关于动态规划:背包问题的主要内容,如果未能解决你的问题,请参考以下文章

分别用回溯法和动态规划求0/1背包问题(C语言代码)

背包动态规划输入

动态规划问题3--多重背包

动态规划问题3--多重背包

动态规划背包问题总结

动态规划之01背包问题(含代码C)