動態規劃 四、基礎揹包問題總結(多重揹包與多重揹包的轉化)

描述ios

有N種物品和一個容量爲V的揹包。第i種物品最多有n[i]件可用,每件費用是c[i],價值是w[i]。求解將哪些物品裝入揹包可以使這些物品的費用總和不超過揹包容量,且價值總和最大。數組

變式:有的物品能只有1個,有的物品有多個。less

狀態轉移方程:ide

dp[i][j]=max{dp[i][j],dp[i-1][j-c[i]*k]+w[i]*k}//0<=k<=n[i];優化

轉化成01揹包:(目的是便於下降空間複雜度)this

轉化成2^n的模版spa

int total=p;//p是當前已知物品的數量
for(int i=1;i<=p;i++){
	int s=1;
	while(n[i]>s){
	       total++;
	       w[total]=w[i]*s; 
	       c[total]=c[i]*s
	       n[i]=n[i]-s;
	       s=s*2;
        }
	w[i]=n[i]*i;
}

 空間優化後的01揹包模型code

//n:拆分合並後的物品的總數量
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++){
    for(int j=v;j>=c[i];j--){
        dp[j]=max(dp[j],dp[j-c[i]]+w[i]);
    }
}
cout<<dp[v]<<endl;
//輸出了最大容量爲v時能達到的最大價值

而後,譚小奎同志告訴了我一個優化的方法。blog

for i=1 to n
 if (c[i]*n[i]>v){
    for j=0 to v
    //看成徹底揹包來作
else{
  二進制拆分紅01揹包
  for(j=v to 0//01揹包

這樣來講,數據很好的話,時間複雜度大大下降了。譚小奎同窗告訴我徹底揹包比01揹包複雜度低不少,我才注意到時間的問題啊,之前一直沒想過~~~~~ip

 題型分析

 參考01揹包那篇博文中的描述。

一、多重揹包的通常性解法,容量不定

Big Event in HDU

 

Description

Nowadays, we all know that Computer College is the biggest department in HDU. But, maybe you don't know that Computer College had ever been split into Computer College and Software College in 2002.
The splitting is absolutely a big event in HDU! At the same time, it is a trouble thing too. All facilities must go halves. First, all facilities are assessed, and two facilities are thought to be same if they have the same value. It is assumed that there is N (0<N<1000) kinds of facilities (different value, different kinds).
 

 

Input

Input contains multiple test cases. Each test case starts with a number N (0 < N <= 50 -- the total number of different facilities). The next N lines contain an integer V (0<V<=50 --value of facility) and an integer M (0<M<=100 --corresponding number of the facilities) each. You can assume that all V are different.
A test case starting with a negative integer terminates input and this test case is not to be processed.
 

 

Output

For each case, print one line containing two integers A and B which denote the value of Computer College and Software College will get respectively. A and B should be as equal as possible. At the same time, you should guarantee that A is not less than B.
 

 

Sample Input

2 10 1 20 1 3 10 1 20 2 30 1 -1
 

 

Sample Output

20 10 40 40
 

 

這是一道典型的多重揹包問題+性價比爲一+裝載無定值

揹包容量是各類設備價值總和的一半。這裏是能夠化成01揹包的,爲體現多重揹包的初始狀態,貼上這個程序。

 

#include<iostream>
#include<string.h>
using namespace std;
int dp[50+5][125000+5];
int w[55];
int nn[55];
int main(){
    int n;
    while(cin>>n && n>=0){
    if(n==0)cout<<"0"<<" "<<"0"<<endl;
    else{
    int m=0;
    for(int i=1;i<=n;i++){
        cin>>w[i]>>nn[i];
        m+=w[i]*nn[i];
    }
    int mm=m;
    m=m/2;
    memset(dp,0,sizeof(dp));
    dp[0][0]=1;
    for(int i=1;i<=n;i++){
        for(int j=0;j<=nn[i];j++){
            for(int k=m;k>=0;k--){
                if(j*w[i]<=k && dp[i-1][k-j*w[i]]==1){
                dp[i][k]=1;
                }
            }
        }
    }
    int ans=0;
    for(int i=m;i>=0;i--){
        for(int j=n;j>=1;j--){
            if(dp[j][i]==1) {ans=i;break;}
        }
        if (ans!=0) break;
    }
    cout<<(mm-ans)<<" "<<ans<<endl;
   }
   }
    return 0;
}

 

二、2次拆分的01解法,容量不定

 

 Dividing

Description

Marsha and Bill own a collection of marbles. They want to split the collection among themselves so that both receive an equal share of the marbles. This would be easy if all the marbles had the same value, because then they could just split the collection in half. But unfortunately, some of the marbles are larger, or more beautiful than others. So, Marsha and Bill start by assigning a value, a natural number between one and six, to each marble. Now they want to divide the marbles so that each of them gets the same total value. Unfortunately, they realize that it might be impossible to divide the marbles in this way (even if the total value of all marbles is even). For example, if there are one marble of value 1, one of value 3 and two of value 4, then they cannot be split into sets of equal value. So, they ask you to write a program that checks whether there is a fair partition of the marbles.

Input

Each line in the input file describes one collection of marbles to be divided. The lines contain six non-negative integers n1 , . . . , n6 , where ni is the number of marbles of value i. So, the example from above would be described by the input-line "1 0 1 2 0 0". The maximum total number of marbles will be 20000.
The last line of the input file will be "0 0 0 0 0 0"; do not process this line.

Output

For each collection, output "Collection #k:", where k is the number of the test case, and then either "Can be divided." or "Can't be divided.".
Output a blank line after each test case.

Sample Input

1 0 1 2 0 0 
1 0 0 0 1 1 
0 0 0 0 0 0 

Sample Output

Collection #1:
Can't be divided.

Collection #2:
Can be divided.

因爲物品數不少,二維數組超空間,一一分配01作法超時間,咱們選擇2次拆分來作。
拆分的模版在上面已經貼出了。接着按照01來作就能夠了。
 1 #include<iostream>
 2 #include<string.h>
 3 #define maxn 420000+5
 4 using namespace std;
 5 int dp[maxn];
 6 int w[100];
 7 int main(){
 8     int t=0;
 9     while(1){
10         t++;
11         int a[10];
12         int m=0;
13         for(int i=1;i<=6;i++){
14             cin>>a[i];
15             m=m+i*a[i];
16         }
17         if (m%2!=0) {
18             cout<<"Collection #"<<t<<":"<<endl;
19             cout<<"Can't be divided."<<endl;
20             cout<<endl;
21             continue;
22         }else
23         {
24         m=m/2;
25         if(a[2]+a[1]+a[3]+a[4]+a[5]+a[6]==0) break;
26         int total=6;
27         for(int i=1;i<=6;i++){
28             int s=1;
29             while(a[i]>s){
30                 total++;
31                 w[total]=i*s; 
32                 a[i]=a[i]-s;
33                 s=s*2;
34             }
35             w[i]=a[i]*i;
36         }//如今已經轉化成01揹包    
37         memset(dp,0,sizeof(dp));
38         dp[0]=1;
39         for(int i=1;i<=total;i++){
40             for(int j=m;j>=w[i];j--){
41                 if (dp[j-w[i]])
42                     dp[j]=1;
43             }
44         }
45         if(!dp[m]) {
46             cout<<"Collection #"<<t<<":"<<endl;
47             cout<<"Can't be divided."<<endl;
48             cout<<endl;
49         }else{
50             cout<<"Collection #"<<t<<":"<<endl;
51             cout<<"Can be divided."<<endl;
52             cout<<endl;
53         }
54     }
55     }
56     return 0;
57 }
相關文章
相關標籤/搜索