背包问题

背包问题有很多种,常见的有01背包,完全背包,多重背包等,这里简单介绍几种,详细的可参考dd_engi大牛的背包九讲

01背包:n件物品放入容量为v的背包,每件物品只有一件,只可以选择放或是不放,求最大价值

模板


  1. void zeroonepack(int cost,int value)  
  2. {  
  3.     int i;  
  4.     for(i=sum;i>=cost;i--)  
  5.     dp[i]=max(dp[i],dp[i-cost]+value);  
  6. }  

HDU-2602-Bone Collector

http://acm.hdu.edu.cn/showproblem.php?pid=2602

基本的01背包,套模板即可


  1. #include<stdio.h>  
  2. #include<string.h>  
  3. #include<stdlib.h>  
  4. int sum;  
  5. int dp[1005];  
  6. int max(int x,int y)  
  7. {  
  8.     return x>y?x:y;  
  9. }  
  10. void zeroonepack(int cost,int value)  
  11. {  
  12.     int i;  
  13.     for(i=sum;i>=cost;i--)  
  14.     dp[i]=max(dp[i],dp[i-cost]+value);  
  15. }  
  16. int main()  
  17. {  
  18.     int i,t,n;  
  19.     int a[1005][2];  
  20.     scanf("%d",&t);  
  21.     while(t--)  
  22.     {  
  23.         scanf("%d%d",&n,&sum);  
  24.         for(i=0;i<n;i++)  
  25.         scanf("%d",&a[i][0]);  
  26.         for(i=0;i<n;i++)  
  27.         scanf("%d",&a[i][1]);  
  28.         memset(dp,0,sizeof(dp));  
  29.         for(i=0;i<n;i++)  
  30.         zeroonepack(a[i][1],a[i][0]);  
  31.         printf("%d\n",dp[sum]);  
  32.     }  
  33.     return 0;  
  34. }  

HDU-2546-饭卡

http://acm.hdu.edu.cn/showproblem.php?pid=2546

这题很有意思,先用贪心,再做01背包


  1. #include<stdio.h>  
  2. #include<string.h>  
  3. #include<stdlib.h>  
  4. int sum;  
  5. int dp[1005],price[1005];  
  6. int max(int x,int y)  
  7. {  
  8.     return x>y?x:y;  
  9. }  
  10. void zeroonepack(int cost,int value)  
  11. {  
  12.     int i;  
  13.     for(i=sum;i>=cost;i--)  
  14.     dp[i]=max(dp[i],dp[i-cost]+value);  
  15. }  
  16. int main()  
  17. {  
  18.     int i,n,temp,k,m;  
  19.     while(scanf("%d",&n),n)  
  20.     {  
  21.         temp=-1;  
  22.         memset(dp,0,sizeof(dp));  
  23.         for(i=0;i<n;i++)  
  24.         {  
  25.             scanf("%d",&price[i]);  
  26.             if(price[i]>temp)  
  27.             {  
  28.                 temp=price[i];  
  29.                 k=i;  
  30.             }  
  31.         }  
  32.         scanf("%d",&m);  
  33.         if(m<5)  
  34.         {  
  35.             printf("%d\n",m);  
  36.             continue;  
  37.         }  
  38.         sum=m-5;  //5元去买价格最大的菜  
  39.         for(i=0;i<n;i++)  //剩下的做01背包  
  40.         if(i!=k)  
  41.         zeroonepack(price[i],price[i]);  
  42.         printf("%d\n",m-price[k]-dp[sum]);  
  43.     }  
  44.     return 0;  
  45. }  

完全背包:n件物品放入容量为v的背包,每种物品有无限件,求最大价值

模板


  1. void completepack(int cost,int value)  
  2. {  
  3.     int i;  
  4.     for(i=cost;i<=sum;i++)  
  5.     dp[i]=max(dp[i],dp[i-cost]+value);  
  6. }  

HDU-1248-寒冰王座

http://acm.hdu.edu.cn/showproblem.php?pid=1248

基本的完全背包

  1. #include<stdio.h>  
  2. #include<string.h>  
  3. #include<stdlib.h>  
  4. int sum,dp[10005];  
  5. int max(int x,int y)  
  6. {  
  7.     return x>y?x:y;  
  8. }  
  9. void completepack(int cost,int value)  
  10. {  
  11.     int i;  
  12.     for(i=cost;i<=sum;i++)  
  13.     dp[i]=max(dp[i],dp[i-cost]+value);  
  14. }  
  15. int main()  
  16. {  
  17.     int t;  
  18.     scanf("%d",&t);  
  19.     while(t--)  
  20.     {  
  21.         scanf("%d",&sum);  
  22.         memset(dp,0,sizeof(dp));  
  23.         completepack(150,150);  
  24.         completepack(200,200);  
  25.         completepack(300,300);  
  26.         printf("%d\n",sum-dp[sum]);  
  27.     }  
  28.     return 0;  
  29. }  

HDU-1963-Investment

http://acm.hdu.edu.cn/showproblem.php?pid=1963

这题也是完全背包,需要注意的是背包的容量在发生变化,The value of a bond isalways a multiple of $1 000,这句话是关键,投资的成本是1000的倍数,本金和成本都除以1000可大大减少循环次数


  1. #include<stdio.h>  
  2. #include<string.h>  
  3. #include<stdlib.h>  
  4. int sum,dp[100001];  
  5. int max(int x,int y)  
  6. {     
  7.     return x>y?x:y;  
  8. }  
  9. void completepack(int cost,int value)  
  10. {  
  11.     int i;  
  12.     for(i=cost;i<=sum;i++)  
  13.     dp[i]=max(dp[i],dp[i-cost]+value);  
  14. }  
  15. int main()  
  16. {  
  17.     int i,n,t,year,money;  
  18.     int a[15][2];  
  19.     scanf("%d",&t);  
  20.     while(t--)  
  21.     {  
  22.         scanf("%d%d%d",&money,&year,&n);  
  23.         for(i=0;i<n;i++)  
  24.         {  
  25.             scanf("%d %d",&a[i][0],&a[i][1]);  
  26.             a[i][0]/=1000;    
  27.         }  
  28.         while(year--)  
  29.         {  
  30.             sum=money/1000;  
  31.             memset(dp,0,sizeof(dp));  
  32.             for(i=0;i<n;i++)  
  33.             completepack(a[i][0],a[i][1]);  
  34.             money+=dp[sum];  
  35.         }  
  36.         printf("%d\n",money);  
  37.     }  
  38.     return 0;  
  39. }  

多重背包:n件物品放入容量为v的背包,每件物品的件数都是有上限的,求最大价值

模板

  1. void multiplepack(int cost,int value,int amount)  
  2. {  
  3.     int k=1;  
  4.     if(cost*amount>=sum)  
  5.     completepack(cost,value);  
  6.     else  
  7.     {  
  8.         while(k<amount)  
  9.         {  
  10.             zeroonepack(k*cost,k*value);  
  11.             amount-=k;  
  12.             k*=2;  
  13.         }  
  14.         zeroonepack(amount*cost,amount*value);  
  15.     }  
  16. }  

HDU-2191-珍惜现在,感恩生活

http://acm.hdu.edu.cn/showproblem.php?pid=2191

基本的多重背包

  1. #include<stdio.h>  
  2. #include<string.h>  
  3. #include<stdlib.h>  
  4. int sum;  
  5. int dp[101];  
  6. int max(int x,int y)  
  7. {  
  8.     return x>y?x:y;  
  9. }  
  10. void zeroonepack(int cost,int value)  
  11. {  
  12.     int i;  
  13.     for(i=sum;i>=cost;i--)  
  14.     dp[i]=max(dp[i],dp[i-cost]+value);  
  15. }  
  16. void completepack(int cost,int value)  
  17. {  
  18.     int i;  
  19.     for(i=cost;i<=sum;i++)  
  20.     dp[i]=max(dp[i],dp[i-cost]+value);  
  21. }  
  22. void multiplepack(int cost,int value,int amount)  
  23. {  
  24.     int k=1;  
  25.     if(cost*amount>=sum)  
  26.     completepack(cost,value);  
  27.     else  
  28.     {  
  29.         while(k<amount)  
  30.         {  
  31.             zeroonepack(k*cost,k*value);  
  32.             amount-=k;  
  33.             k*=2;  
  34.         }  
  35.         zeroonepack(amount*cost,amount*value);  
  36.     }  
  37. }  
  38. int main()  
  39. {  
  40.     int t;  
  41.     int n,a,b,c;  
  42.     scanf("%d",&t);  
  43.     while(t--)  
  44.     {  
  45.         scanf("%d%d",&sum,&n);  
  46.         memset(dp,0,sizeof(dp));  
  47.         while(n--)  
  48.         {  
  49.             scanf("%d%d%d",&a,&b,&c);  
  50.             multiplepack(a,b,c);  
  51.         }  
  52.         printf("%d\n",dp[sum]);  
  53.     }  
  54.     return 0;  
  55. }  

POJ-1014-Dividing

http://poj.org/problem?id=1014

这题也是多重背包,要想均分,只要一半容量的背包最大能容下一半的价值即可

  1. #include<stdio.h>  
  2. #include<string.h>  
  3. #include<stdlib.h>  
  4. int sum,dp[60005];  
  5. int max(int x,int y)  
  6. {  
  7.     return x>y?x:y;  
  8. }  
  9. void zeroonepack(int cost,int value)  
  10. {  
  11.     int i;  
  12.     for(i=sum;i>=cost;i--)  
  13.     dp[i]=max(dp[i],dp[i-cost]+value);  
  14. }  
  15. void completepack(int cost,int value)  
  16. {  
  17.     int i;  
  18.     for(i=cost;i<=sum;i++)  
  19.     dp[i]=max(dp[i],dp[i-cost]+value);  
  20. }  
  21. void multiplepack(int cost,int value,int amount)  
  22. {  
  23.     int k=1;  
  24.     if(cost*amount>=sum)  
  25.     completepack(cost,value);  
  26.     else  
  27.     {  
  28.         while(k<amount)  
  29.         {  
  30.             zeroonepack(k*cost,k*value);  
  31.             amount-=k;  
  32.             k*=2;  
  33.         }  
  34.         zeroonepack(cost*amount,value*amount);  
  35.     }  
  36. }  
  37. int main()  
  38. {  
  39.     int i,cases=1;  
  40.     int num[6];  
  41.     while(scanf("%d%d%d%d%d%d",&num[0],&num[1],&num[2],&num[3],&num[4],&num[5]))  
  42.     {  
  43.         if(num[0]==0&&num[1]==0&&num[2]==0&&num[3]==0&&num[4]==0&&num[5]==0)  
  44.         break;  
  45.         sum=0;  
  46.         for(i=0;i<6;i++)  
  47.         sum+=(i+1)*num[i];  
  48.         printf("Collection #%d:\n",cases++);  
  49.         if(sum&1)   //若sum为奇数,一定不能均分  
  50.         {  
  51.               printf("Can't be divided.\n\n");   
  52.               continue;    
  53.         }   
  54.         sum>>=1;  
  55.         memset(dp,0,sizeof(dp));  
  56.         for(i=0;i<6;i++)  
  57.         if(num[i]!=0)  
  58.         multiplepack(i+1,i+1,num[i]);  
  59.         if(dp[sum]==sum)  
  60.         printf("Can be divided.\n\n");  
  61.         else  
  62.         printf("Can't be divided.\n\n");  
  63.     }  
  64.     return 0;  
  65. }  

你可能感兴趣的:(背包问题)