1. 程式人生 > >【動態規劃】背包問題相關題目

【動態規劃】背包問題相關題目

scanf man 初始 ads 無法 ger %d val more

1.poj 1742

Description

People in Silverland use coins.They have coins of value A1,A2,A3...An Silverland dollar.One day Tony opened his money-box and found there were some coins.He decided to buy a very nice watch in a nearby shop. He wanted to pay the exact price(without change) and he known the price would not more than m.But he didn‘t know the exact price of the watch.
You are to write a program which reads n,m,A1,A2,A3...An and C1,C2,C3...Cn corresponding to the number of Tony‘s coins of value A1,A2,A3...An then calculate how many prices(form 1 to m) Tony can pay use these coins.

Input

The input contains several test cases. The first line of each test case contains two integers n(1<=n<=100),m(m<=100000).The second line contains 2n integers, denoting A1,A2,A3...An,C1,C2,C3...Cn (1<=Ai<=100000,1<=Ci<=1000). The last test case is followed by two zeros.

Output

For each test case output the answer on a single line.

Sample Input

3 10
1 2 4 2 1 1
2 5
1 4 2 1
0 0

Sample Output

8
4

題解:

  可以看出問題屬於背包問題,且每件物品選取次數有限制,故為多重背包問題。而且此題沒有涉及到最大價值問題,為之前講的多重背包的變體。令dp[i+1][j]為取前i種硬幣加和為j後第i種硬幣最多剩余數,則dp[i][j] >= 0說明price = j可以達到,否則就是無法達到。

Solution 1

#include <cstdio>  
#include <cstring>  
#include <iostream>  
#include <algorithm>
using
namespace std; int dp[100000 + 5]; int w[100 + 5], v[100 + 5]; int n, m; int main(){ int i, j ,res; while(scanf("%d%d", &n, &m) != EOF && (m || n)){ for(i = 0; i < n; ++i){ scanf("%d", &w[i]); } for(i = 0; i < n; ++i){ scanf("%d", &v[i]); } memset(dp, -1, sizeof(dp)); dp[0] = 0; for(i = 0; i < n; ++i){ for(j = 0; j <= m; ++j){ if(dp[j] >= 0) { dp[j] = v[i]; } else if(j < w[i] || dp[j - w[i]] <= 0){ dp[j] = -1; } else { dp[j] = dp[j - w[i]] - 1; } } } res = 0; for(i = 1; i <= m; ++i){ if(dp[i] >= 0) ++res; } printf("%d\n", res); } return 0; }

Solution 2

#include <cstdio>  
#include <cstring>  
#include <iostream>  

using namespace std;
int dp[100000 + 5], used[100000 + 5];
int w[100 + 5], v[100 + 5];
int n, m;

int main(){
  int res;
  while(scanf("%d%d", &n, &m) != EOF && (m || n)){
      for(int i = 0; i < n; ++i){
        scanf("%d", &w[i]);
      }
      for(int i = 0; i < n; ++i){
        scanf("%d", &v[i]);
      }
      memset(dp, 0, sizeof(dp));
      dp[0] = 1;
res = 0; for(int i = 0; i < n; ++i){ memset(used, 0, sizeof(used)); for(int j = w[i]; j <= m; ++j){ if(!dp[j] && dp[j - w[i]] && used[j - w[i]] < v[i]){ dp[j] = 1; used[j] = used[j - w[i]] + 1; ++res; } } } printf("%d\n", res); } return 0; }

  其中dp[j]表示能否加和為j。used[j]表示最少要用多少個w[i]能加和達到j。

  從此題可知,多重背包模板還可以為

dp初始化,因題而異
for(int i = 0; i < n; ++i){
    memset(used, 0, sizeof(used));
    for(int j = w[i]; j <= MAX_M; ++j){
        if(!dp[j] && dp[j - w[i] && used[j - w[i]] < v[i]){
            ...對dp的操作及其他操作,因題而異
            used[j] = used[j - w[i]] + 1;//想要達到j最少使用w[i]的個數。
        }
    }
}

  

2.

【動態規劃】背包問題相關題目