zoukankan      html  css  js  c++  java
  • 简单的背包问题(入门)HDU2602 HDU2546 HDU1864

    动态规划,我一直都不熟悉,因为体量不够,所以今天开始努力地学习学习。

    当然背包从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
    ",res);
    
    
    
         }
    
    
    
         return 0;
    }
    



  • 相关阅读:
    Volume serial number could associate file existence on certain volume
    分区表收集统计信息
    数据泵导入外键表数据报错
    Oracle备份优化开启块改变跟踪
    Oracle asm lib存储扩容及测试
    ASM_Lib_linux_redhat6.9添加asm磁盘扩容
    ogg清理无法自动清理导致占用大量空间处理
    应用复制进程abend,报错OGG-01163字段列长度不够
    历史备份过多使用delete obsolete方式找不到过期备份信息???
    测试使用块跟踪文件
  • 原文地址:https://www.cnblogs.com/dengyaolong/p/3697244.html
Copyright © 2011-2022 走看看