簡單的揹包問題(入門)HDU2602 HDU2546 HDU1864

weixin_30924079發表於2020-04-04

動態規劃,我一直都不熟悉,因為體量不夠,所以今天開始努力地學習學習。

當然揹包從01開始,先選擇了一個簡單的經典的揹包HDU2602。

Many years ago , in Teddy’s hometown there was a man who was called “Bone Collector”. This man like to collect varies of bones , such as dog’s , cow’s , also he went to the grave …
The bone collector had a big bag with a volume of V ,and along his trip of collecting there are a lot of bones , obviously , different bone has different value and different volume, now given the each bone’s value along his trip , can you calculate out the maximum of the total value the bone collector can get ?

The first line contain a integer T , the number of cases.
Followed by T cases , each case three lines , the first line contain two integer N , V, (N <= 1000 , V <= 1000 )representing the number of bones and the volume of his bag. And the second line contain N integers representing the value of each bone. The third line contain N integers representing the volume of each bone.

One integer per line representing the maximum of the total value (this number will be less than 231).

Input

1
5 10
1 2 3 4 5
5 4 3 2 1
Output

14
C++程式碼

/*******************************************************************************/
/* OS           : 3.2.0-58-generic #88-Ubuntu SMP Tue Dec 3 UTC 2013 GNU/Linux
 * Compiler     : g++ (GCC)  4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)
 * Encoding     : UTF8
 * Date         : 2014-03-08
 * All Rights Reserved by yaolong.
*****************************************************************************/
/* Description: ***************************************************************
*****************************************************************************/
/* Analysis: ******************************************************************
*****************************************************************************/
/*****************************************************************************/


#include <iostream>
#include <cstring>
int max(int a,int b){
   return a>b?a:b;

}
using namespace std;
int dp[1003];
int v[1003];
int w[1003];
int main(){
    int cases,i,j,val,n;
    cin>>cases;
    while(cases--){
        memset(dp,0,sizeof(dp));
        memset(v,0,sizeof(v));
        memset(w,0,sizeof(w));
        cin>>n>>val;
        for(i=1;i<=n;i++){
           cin>>w[i];
        }
        for(i=1;i<=n;i++){
           cin>>v[i];
        }
        for(i=1;i<=n;i++)
           for(j=val;j>=v[i];j--)
              dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
        cout<<dp[val]<<endl;

    }

     return 0;
}




後來特意選了一道HDU的簡單揹包問題。HDU的2546。

題目很簡單:

 電子科大本部食堂的飯卡有一種很詭異的設計,即在購買之前判斷餘額。如果購買一個商品之前,卡上的剩餘金額大於或等於5元,就一定可以購買成功(即使購買後卡上餘額為負),否則無法購買(即使金額足夠)。所以大家都希望儘量使卡上的餘額最少。
某天,食堂中有n種菜出售,每種菜可購買一次。已知每種菜的價格以及卡上的餘額,問最少可使卡上的餘額為多少。

 多組資料。對於每組資料:
第一行為正整數n,表示菜的數量。n<=1000。
第二行包括n個正整數,表示每種菜的價格。價格不超過50。
第三行包括一個正整數m,表示卡上的餘額。m<=1000。

n=0表示資料結束。

對於每組輸入,輸出一行,包含一個整數,表示卡上可能的最小余額。

其實這道題在01揹包上多了一個彎,就是卡餘額大於等於5可以購買任何東西。只要留下5元買最貴的東西,剩下的就是一個揹包問題了。

/*******************************************************************************/
/* OS           : 3.2.0-58-generic #88-Ubuntu SMP Tue Dec 3 UTC 2013 GNU/Linux
 * Compiler     : g++ (GCC)  4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)
 * Encoding     : UTF8
 * Date         : 2014-03-08
 * All Rights Reserved by yaolong.
 *****************************************************************************/
/* Description: ***************************************************************
 *****************************************************************************/
/* Analysis: ******************************************************************
 *****************************************************************************/
/*****************************************************************************/
//*

#include <iostream>
#include <cstring>

using namespace std;
int min(int a,int b){
   return a>b?b:a;
}
int main()

{
    int n,i,j,V;
    int c[1002];
    int f[1002];

    while(cin>>n&&n){
        int max=0,mi=0;
       for(i=1;i<=n;i++){
         cin>>c[i];
         //cout<<c[i];
         if(c[i]>max){
            max=c[i];
            mi=i;
         }
       }
       cin>>V;
      if(V<5){
         cout<<V<<endl;
      }else{

       for(j=0;j<=V;j++)
          f[j]=V;
          V-=5;
       for(i=1;i<=n;i++)
           if(i!=mi)
          for(j=V;j>=c[i];j--){
             f[j]=min(f[j],f[j-c[i] ]-c[i]);
          }


          cout<<f[V]-c[mi]<<endl;


      }
    }



    return 0;

}


對於HDU1864這題目,則是明顯的01揹包,但是其中要做一些小小的處理。

我的方法很一般,而且效率也不怎麼高,就算是很傳統吧。如果用C語言寫的話會略去一些沒必要的字串處理過程。

因為題目是兩位小數的,所以我很暴力地全部*100,空間浪費了很多,但是500000的空間能過。


現有一筆經費可以報銷一定額度的發票。允許報銷的發票型別包括買圖書(A類)、文具(B類)、差旅(C類),要求每張發票的總額不得超過1000元,每張發票上,單項物品的價值不得超過600元。現請你編寫程式,在給出的一堆發票中找出可以報銷的、不超過給定額度的最大報銷額。

測試輸入包含若干測試用例。每個測試用例的第1行包含兩個正數 Q 和 N,其中 Q 是給定的報銷額度,N(<=30)是發票張數。隨後是 N 行輸入,每行的格式為:
m Type_1:price_1 Type_2:price_2 ... Type_m:price_m
其中正整數 m 是這張發票上所開物品的件數,Type_i 和 price_i 是第 i 項物品的種類和價值。物品種類用一個大寫英文字母表示。當N為0時,全部輸入結束,相應的結果不要輸出。

程式碼:

/*******************************************************************************/
/* OS           : 3.2.0-58-generic #88-Ubuntu SMP Tue Dec 3 UTC 2013 GNU/Linux
 * Compiler     : g++ (GCC)  4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)
 * Encoding     : UTF8
 * Date         : 2014-03-08
 * All Rights Reserved by yaolong.
 *****************************************************************************/
/* Description: ***************************************************************
 *****************************************************************************/
/* Analysis: ******************************************************************
 *****************************************************************************/
/*****************************************************************************/
//*

#include <iostream>
#include <string>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <iomanip>

using namespace std;
int max(int a,int b){
  return a>b?a:b;
}
int f[5000000];
int main()

{
    float money;
    int n,m,i,j;
    string tmp;
    float c[32];
    //float f[32];

    int ci[32];
    int moneyi;
   // freopen("input.txt","r",stdin);
    while(cin>>money>>n&&n){
        memset(f,0,sizeof(f));
         memset(c,0.0f,sizeof(c));
       for(i=1;i<=n;i++){
        cin>>m;
        int flag=1;
         float A,B,C;
          A=B=C=0.0f;
        while(m--){
          cin>>tmp;

          float a;

         if(tmp[0]=='A'){
             tmp.erase(0,1);
             tmp.erase(0,1);
             a=atof(tmp.c_str());
              A+=a;

         }else if(tmp[0]=='C'){
             tmp.erase(0,1);
             tmp.erase(0,1);
             a=atof(tmp.c_str());
             C+=a;


         }else if(tmp[0]=='B'){
             tmp.erase(0,1);
             tmp.erase(0,1);
             a=atof(tmp.c_str());
             B+=a;

         }else{
             flag=0;

               }
         }
         if(flag&&A+B+C<=1000.0f&&A<=600.0F&&B<=600.0F&&C<=600.0f){
            c[i]=A+B+C;

         }else{
            c[i]=0;
         }
         //cout
        // cout<<c[i]<<endl;
        }
        for(i=1;i<=n;i++){
            //cout<<100*c[i];
          ci[i]=(int)(100*c[i]);
        //   cout<<"ci[i]"<<ci[i]<<endl;

        }
        moneyi=(int)(money*100);
        //cout<<"m="<<moneyi<<endl;
        for(i=1;i<=n;i++)
           for(j=moneyi;j>=ci[i];j--){
              f[j]=max(f[j],f[j-ci[i]]+ci[i]);

           }
           double xs=f[moneyi]/100.0;
           cout<<setprecision(2) <<std::fixed<<xs<<endl;



    }
  //    fclose(stdin);  //關閉檔案



    return 0;

}

C程式碼:

/*******************************************************************************/
/* OS           : 3.2.0-58-generic #88-Ubuntu SMP Tue Dec 3 UTC 2013 GNU/Linux
 * Compiler     : GCC  4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)
 * Encoding     : UTF8
 * Date         : 2014-03-08
 * All Rights Reserved by yaolong.
*****************************************************************************/
/* Description: ***************************************************************
*****************************************************************************/
/* Analysis: ******************************************************************
*****************************************************************************/
/*****************************************************************************/



#include <stdio.h>
#include <string.h>

int main(){

     double money,A,B,C,tmp;
     int n,m,i,j,flag;
     char c;
     double dp[32];
     double w[32];

     while(scanf("%lf%d",&money,&n)!=EOF&&n){

          memset(w,0,sizeof(w));
          memset(dp,0,sizeof(dp));
          for(i=1;i<=n;i++){

             scanf("%d",&m);
             A=B=C=0;
             flag=1;
             for(j=1;j<=m;j++){

                scanf(" %c:%lf",&c,&tmp);

                if(c=='A'){
                    A+=tmp;
                }else if(c=='B'){
                   B+=tmp;
                }else if(c=='C'){
                   C+=tmp;

                }else{
                   flag=0;
                }

             }
             if(flag&&A<=600.0&&B<=600.0&&C<=600.0&&A+B+C<=1000.0){
                   w[i]=A+B+C;
                }else{
                   w[i]=0.0;
                }



          }

          for(i=1;i<=n;i++)
             for(j=n;j>=1;j--)
                 if(money-w[j]>=dp[j-1]||j==1)
                dp[j]=(dp[j]>dp[j-1]+w[i])?dp[j]:dp[j-1]+w[i];

          double res=0;
          for(i=1;i<=n;i++){
             if(res<=dp[i]) res=dp[i];

          }
           printf("%.2lf\n",res);



     }



     return 0;
}



轉載於:https://www.cnblogs.com/dengyaolong/p/3697244.html

相關文章