0-1背包问题,附上例题(POJ - 3624 Charm Bracelet)

0-1背包问题的题目样式

有 N 件物品和一个容量为 M 的背包。放入第 i 件物品耗费的费用是 Wi,得到的价值是 Vi。求解将哪些物品装入背包可使价值总和最大。

0-1背包问题关键在于该物品放或不放,即在当前容量为M的的情况下,选择不选择该物品,那么就有一个转移方程

for(i=0  -  N)

  for(j= M - w[i])

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

当前物品为i,当前的背包容量为j,如果不选当前该物品,则选取dp[i-1][j]该值。如果选择当前物品,则选取dp[i-1][j+w[i]]+v[i]该值,从两个值当中选取大的值。

最后在dp[N][]中选出最大的,为总和最大的答案

 

0-1背包的方程优化

  上一个转移方程解法,在时间上已基本无法优化,只能在空间上进行优化。从O(NM)-> O(M)

转移方程变为

for(j=M  -  w[i])

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

下面解释一下为什么该方程可行:

因为w[i]是个正数,即j+w[i] > j肯定是成立的,j <=j 且j <=j+w[i],所以对于下一次循环j+1肯定不会取到j+1之前的值,所以该转移方程对后续没有影响,是成立的。

最后找出dp[]中最大的就行

 

给出一道0-1背包的例题

POJ - 3624    http://poj.org/problem?id=3624

 

     Charm Bracelet

 

Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 40985   Accepted: 17828

 

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

未优化的代码,提交上去是(Memory Limit Exceeded),因为空间复杂度太大
 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 #include <algorithm>
 5 using namespace std;
 6 int dp[3500][13000];
 7 int main()
 8 {
 9     int n , m ;
10     int w[3500], v[3500];
11 
12     while(scanf("%d%d",&n,&m) != EOF) {
13         for(int i= 1 ; i <= n ; i++)
14             scanf("%d%d",&w[i],&v[i]);
15         for(int i = 1 ; i <= n; i++) {
16             for(int  j = 0; j <= m; j++) {
17                 if(j+w[i] <= m)
18                     dp[i][j] = max(dp[i-1][j],dp[i-1][j+w[i]]+v[i]);
19                 else dp[i][j] = dp[i-1][j];
20             }
21         }
22         int ans =0;
23         for(int j = 0; j <= m; j++)
24             ans = dp[n][j] > ans ? dp[n][j]:ans;
25         printf("%d\n",ans);
26     }
27     return 0;
28 }

 




下面给出优化的代码(accpeted)
 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 #include <algorithm>
 5 using namespace std;
 6 int dp[13000];
 7 int main()
 8 {
 9     int n , m ;
10     int w[3500], v[3500];
11 
12     while(scanf("%d%d",&n,&m) != EOF) {
13         for(int i= 1 ; i <= n ; i++)
14             scanf("%d%d",&w[i],&v[i]);
15         for(int i = 1 ; i <= n; i++) {
16             for(int  j = 0; j <= m; j++) {
17                 if(j+w[i] <= m)
18                     dp[j] = max(dp[j],dp[j+w[i]]+v[i]);
19                 else dp[j] = dp[j];
20             }
21         }
22         int ans =0;
23         for(int j = 0; j <= m; j++)//
24             ans = dp[j] > ans ? dp[j]:ans;
25         printf("%d\n",ans);
26     }
27     return 0;
28 }

 


 

posted @ 2017-08-19 10:57  启动  阅读(785)  评论(0编辑  收藏  举报