背包问题总结

 我对于dp的使用仍然很不熟练,总结一下各种背包梳理一下。

 

01背包

1 void Knapsack_01(){
2     memset(dp,0,sizeof(dp));
3     for(int i=0;i<n;i++){
4         for(int j=W;j>=w[i];j--){
5             dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
6         }
7     }
8     printf("%d\n",dp[W]);
9 }

完全背包

1 void Knapsack_prefect(){
2     memset(dp,0,sizeof(dp));
3     for(int i=0;i<n;i++){
4         for(int j=w[i];j<=W;j++){
5             dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
6         }
7     }
8     printf("%d\n",dp[W]);
9 }

w很大的01背包

 1 void BigW_01(){
 2     memset(dp,0x3f,sizeof(dp));
 3     dp[0]=0;
 4     for(int i=0;i<n;i++){
 5         for(int j=MAX_N*MAX_V;j>=v[i];j--){
 6             dp[j]=min(dp[j],dp[j-v[i]]+w[i]);
 7         }
 8     }
 9     int ans=0;
10     for(int i=0;i<=MAX_N*MAX_V;i++)if(dp[i]<=W)ans=i;
11     printf("%d\n",ans);
12 }

w很大的完全背包

 1 void BigW_prefect(){
 2     memset(dp,0x3f,sizeof(dp));
 3     dp[0]=0;
 4     for(int i=0;i<n;i++){
 5         for(int j=v[i];j<=MAX_N*MAX_V;j++){
 6             dp[j]=min(dp[j],dp[j-v[i]]+w[i]);
 7         }
 8     }
 9     int ans=0;
10     for(int i=0;i<=MAX_N*MAX_V;i++)if(dp[i]<=W)ans=i;
11     printf("%d\n",ans);
12 }

多重背包

复杂度O(nWlog(m))。

算法思想是可以利用1,2,4,…,2k+a来表示一个数,因此,可以把m个相同物品看作是log(m)种不同的物品做01背包求解。

总之mi=1+2+4+…+a(0<=a<2k+1)

这样问题就转化为了nlog(m)个物品求01背包。

本题还有另一种复杂度为O(nW)的做法,利用了双端队列滑动最小值的思想,反正我是没看懂。之后看懂了补上。

 1 void knapsack_multi(){
 2     memset(dp,0,sizeof(dp));
 3     for(int i=0;i<n;i++){
 4         int num=m[i];
 5         for(int k=1;num>0;k<<=1){
 6             int mul=min(k,num);
 7             for(int j=W;j>=w[i]*mul;j--){
 8                 dp[j]=max(dp[j],dp[j-w[i]*mul]+v[i]*mul);
 9             }
10             num-=mul;
11         }
12     }
13     printf("%d\n",dp[W]);
14 }

 

posted on 2018-05-04 15:32  Best_Efforts  阅读(151)  评论(0编辑  收藏  举报

导航