动态规划:背包问题
背包问题
- 有一个背包(限定条件:对可选的东西进行限制),从一堆物品中选择若干放进背包,使得最后背包中的价值是最大的
- 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 }
完全背包
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 }