zoukankan      html  css  js  c++  java
  • hdu和poj的基础dp30道

    题目转自:https://crazyac.wordpress.com/dp%E4%B8%93%E8%BE%91/

    1.hdu 1864 最大报销额

    唔,用网上的算法连自己的数据都没过,hdu的数据居然就过了。。垃圾数据。。

    比如这个:100.00 3

                     1 A:1000.00

                     1 A:200.50

                     1 A:100.00

    输出应该是100.00,然而网上的算法输出是200.50。。hdu的discuss区也是一片骂声。。看到有人说测试数据都是两位小数的(但题目没说),那就每个数据都乘100然后用01背包做吧。。。虽然显然慢了很多。。但实在忍不了网上的错误算法。。。

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    using namespace std;
    
    vector<double> fp;
    int dp[3000005],Q;
    
    void ZeroOnePack(int w)
    {
        for(int i=Q;i-w>=0;i--)
            dp[i]=max(dp[i],dp[i-w]+w);
    }
    
    int main()
    {
        double q;
        int n;
        while(~scanf("%lf%d",&q,&n))
        {
            if(n==0) break;
            Q=q*100;
            fp.clear();
            for(int i=0;i<n;i++)
            {
                int m;
                char lx,mh;
                double p,a=0,b=0,c=0;
                bool flag=1;
                scanf("%d",&m);
                for(int j=0;j<m;j++)
                {
                    cin>>lx>>mh;
                    scanf("%lf",&p);
                    if(lx=='A') a+=p;
                    else if(lx=='B') b+=p;
                    else if(lx=='C') c+=p;
                    else flag=0;
                }
                if(a<=600&&b<=600&&c<=600&&a+b+c<=1000&&flag)
                    fp.push_back((a+b+c)*100);
            }
            int len=fp.size();
            memset(dp,0,sizeof(dp));
            for(int i=0;i<len;i++)
                ZeroOnePack(fp[i]);
            double ans=dp[Q]/100.0;
            printf("%.2lf
    ",ans);
        }
        return 0;
    }

    2.hdu 1203 I Need A Offer

    嘛,概率论。。求“得到至少一份offer的最大概率”==“一份offer都没得到的最小概率”

    还是01背包,背包总量为n,每份offer对应cost值和percentage值,因为要算没得到offer的最小概率,所以保存概率的时候,保存1-percentage,dp[i]=min(dp[i],dp[i-cost]*percent),最后结果为(double)100-(dp[n]*100)%

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    
    struct sc
    {
        int cost;
        double per;
    }a[10005];
    int n,m;
    double dp[10005];
    
    void zopack()
    {
        for(int i=0;i<=n;i++)
                dp[i]=1;
        for(int k=0;k<m;k++)
        {
            for(int i=n;i-a[k].cost>=0;i--)
            {
                if(dp[i-a[k].cost]*a[k].per<dp[i])
                    dp[i]=dp[i-a[k].cost]*a[k].per;
            }
        }
    }
    
    int main()
    {
        while(scanf("%d%d",&n,&m)&&n+m)
        {
            double percent;
            for(int i=0;i<m;i++)
            {
                scanf("%d%lf",&a[i].cost,&percent);
                a[i].per=1.0-percent;
            }
            zopack();
            double ans=(1.0-dp[n])*100;
            printf("%.1lf%%
    ",ans);
        }
        return 0;
    }

    3.hdu 2955 Robberies

    小偷要抢n个银行,当总逃走失败概率低于p时,成功逃走,依次输入在第i个银行要抢mi元,逃走失败概率为pi,问最多能抢走多少钱?

    那么只要看抢了x个银行,成功概率大于1-p即可。

    还是01背包,但是要注意:这道题,weight价值是成功概率1-pi,银行被抢的总值sum作为背包容量,cost花费是mi,然后根据01背包的dp值表格,我们知道i越接近sum,dp值越大,那么从sum开始i--进行遍历,找到第一个dp[i]大于等于总成功概率1-p的,此时的i就是最多能抢走的钱数。

    //关于dp数组的初始化:由于要取max值,所以全部初始化为0,又因为dp[0]表示一个银行都没抢,此时的成功逃跑概率为1,故dp[0]=1

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    double dp[10005];
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--)
        {
            double p,per[105];
            int n,cost[105],sum=0;
            scanf("%lf %d",&p,&n);
            p=1.0-p;
            for(int i=0;i<n;i++)
            {
                scanf("%d %lf",&cost[i],&per[i]);
                sum+=cost[i];
                per[i]=1.0-per[i];
            }
            for(int i=0;i<=sum;i++)
                dp[i]=0.0;
            dp[0]=1.0;//一个银行都不抢 成功逃走的概率为1
            for(int k=0;k<n;k++)
                for(int i=sum;i-cost[k]>=0;i--)
                    dp[i]=max(dp[i],dp[i-cost[k]]*per[k]);
            int i;
            for(i=sum;i>=0;i--)
                if(dp[i]>=p) break;
            printf("%d
    ",i);
        }
        return 0;
    }

    4.poj 2063 Investment

    买基金。。最开始有本金sum,可供购买的基金有d种,打算买y年,每年结束本金会改变,此时可以更改购买方案。按照每年来看的话,其实就是完全背包,背包容量为sum,且容量sum每年都需更新,背包里有d种物品,第i件物品费用为购买价,价值为利润。

    由于每种基金的购买价都是1000的倍数,利润不大于10%,本金最多1,000,000,最多买40年

    至多可得到(1,000,000+((1+10%)^40))/1000=45259    所以dp数组开到46000

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    struct node
    {
        int cost,weight;
    }a[15];
    int dp[46000];
    
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--)
        {
            int sum,year;
            scanf("%d %d",&sum,&year);
            int d;
            scanf("%d",&d);
            for(int i=0;i<d;i++)
            {
                scanf("%d %d",&a[i].cost,&a[i].weight);
                a[i].cost/=1000;
            }
            int limit=sum;
            for(int y=0;y<year;y++)
            {
                memset(dp,0,sizeof(dp));
                for(int k=0;k<d;k++)
                    for(int i=a[k].cost;i<=limit/1000;i++)
                        dp[i]=max(dp[i],dp[i-a[k].cost]+a[k].weight);
                limit+=dp[limit/1000];
            }
            printf("%d
    ",limit);
        }
        return 0;
    }

    5.poj 2392 Space Elevator

    哈哈哈哈哈哈可以叫堆塔吗这题

    有k种塔,分别给出每种塔的高度h和数目c,以及限制高度a(往上堆某种塔的时候不能超过它对应的a),问最多能堆多高?

    这题用多重背包解,一开始把quantity看成quality还想说给我质量干嘛。。还打算用完全背包来着。。。

    这题的数据得排下序,根据a的大小排升序,讲道理的话,a小的不就得先把它给堆了嘛。

    重点!想当然的以为dp[最大的a]就是最大值了,其实不是啊。。所以还得遍历一遍dp来找最大值。。。不然就wa了

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    
    struct block
    {
        int h,a,c;
    }bl[405];
    int dp[400005];
    
    void zop(int c,int w,int v)
    {
        for(int i=v;i>=c;i--)
            dp[i]=max(dp[i],dp[i-c]+w);
    }
    
    void cp(int c,int w,int v)
    {
        for(int i=c;i<=v;i++)
            dp[i]=max(dp[i],dp[i-c]+w);
    }
    
    void mp(int c,int w,int num,int v)
    {
        if(c*num>=v)
        {
            cp(c,w,v);
            return ;
        }
        int k=1;
        while(k<num)
        {
            zop(k*c,k*w,v);
            num-=k;
            k<<=1;
        }
        zop(num*c,num*w,v);
    }
    
    bool cmp(block x,block y)
    {
        return x.a<y.a;
    }
    
    int main()
    {
        int k;
        scanf("%d",&k);
        for(int i=0;i<k;i++)
            scanf("%d%d%d",&bl[i].h,&bl[i].a,&bl[i].c);
        sort(bl,bl+k,cmp);
        memset(dp,0,sizeof(dp));
        for(int i=0;i<k;i++)
            mp(bl[i].h,bl[i].h,bl[i].c,bl[i].a);
        int ans=0;
        for(int i=0;i<=bl[k-1].a;i++)
            ans=max(ans,dp[i]);
        printf("%d
    ",ans);
        return 0;
    }

    6.poj 1276 Cash Machine

    道理跟上一题一样的,直接贴代码了,比上一题还简单,不用排序了,limit只有一个总的。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    int cash,n,num[15],d[15],dp[100005];
    
    void zop(int c,int w)
    {
        for(int i=cash;i>=c;i--)
            dp[i]=max(dp[i],dp[i-c]+w);
    }
    
    void cp(int c,int w)
    {
        for(int i=c;i<=cash;i++)
            dp[i]=max(dp[i],dp[i-c]+w);
    }
    
    void mp(int c,int w,int num)
    {
        if(num*c>=cash)
        {
            cp(c,w);
            return ;
        }
        int k=1;
        while(k<num)
        {
            zop(k*c,k*w);
            num-=k;
            k<<=1;
        }
        zop(num*c,num*w);
    }
    
    int main()
    {
        while(~scanf("%d%d",&cash,&n))
        {
            for(int i=0;i<n;i++)
                scanf("%d%d",&num[i],&d[i]);
            memset(dp,0,sizeof(dp));
            for(int i=0;i<n;i++)
                mp(d[i],d[i],num[i]);
            int ans=0;
            for(int i=0;i<=cash;i++)
                ans=max(ans,dp[i]);
            printf("%d
    ",ans);
        }
        return 0;
    }

    7.hdu 2059 龟兔赛跑

    作dp滚动的时候,开n+2的数组,从起点0到L一直往前滚,对于第i种([1,n+1])状态(从第一站到终点),遍历j 从[0,i)的状态,比较j站到i站之间的距离len与充满电最远行程c的大小,如果len大,就分两段(前c->vt1,后len-c->vt2)算时间,否则就全程len按速度vt1算时间,比较得出这j种状态(即直接从第j站到第i站,中间不停)中的最小值,即为dp[i]的值。

    那么乌龟所用时间就是dp[n+1]啦,要用double存数据,和兔子所用时间L*1.0/vr比较。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    int main()
    {
        int l;
        while(~scanf("%d",&l))
        {
            int n,c,t;
            int vr,vt1,vt2;
            int p[105];
            double dp[105];
            scanf("%d%d%d",&n,&c,&t);
            scanf("%d%d%d",&vr,&vt1,&vt2);
            for(int i=1;i<=n;i++)
                scanf("%d",&p[i]);
            p[0]=0;p[n+1]=l;
            dp[0]=0;
            double minn,temp;
            for(int i=1;i<=n+1;i++)
            {
                minn=10e8;
                for(int j=0;j<i;j++)
                {
                    temp=dp[j];
                    if(j) temp+=t;//充电需要时间,但第一次不用充电
                    int len=p[i]-p[j];
                    if(len>c)
                        temp+=(len-c)*1.0/vt2+c*1.0/vt1;
                    else temp+=len*1.0/vt1;
                    minn=min(minn,temp);
                }
                dp[i]=minn;
            }
            if(dp[n+1]<l*1.0/vr)
                printf("What a pity rabbit!
    ");
            else printf("Good job,rabbit!
    ");
        }
        return 0;
    }

    8.hdu 1059 Dividing

    因为要判断能不能平分,所以sum如果为奇数就不行,否则,用多重背包(因为每种球都给了number数),容量v为sum的一半,然后看dp[v]是否等于另一半sum-v。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    int dp[120005],v;
    void zop(int c,int w)
    {
        for(int i=v;i>=c;i--)
            dp[i]=max(dp[i],dp[i-c]+w);
    }
    
    void cp(int c,int w)
    {
        for(int i=c;i<=v;i++)
            dp[i]=max(dp[i],dp[i-c]+w);
    }
    
    void mp(int c,int w,int num)
    {
        if(c*num>=v)
        {
            cp(c,w);
            return ;
        }
        int k=1;
        while(k<num)
        {
            zop(k*c,k*w);
            num-=k;
            k<<=1;
        }
        zop(num*c,num*w);
    }
    
    int main()
    {
        int n[7];
        int cas=0;
        while(scanf("%d%d%d%d%d%d",&n[0],&n[1],&n[2],&n[3],&n[4],&n[5])&&n[0]+n[1]+n[2]+n[3]+n[4]+n[5])
        {
            cas++;
            int sum=0;
            for(int i=0;i<6;i++)
                sum+=(i+1)*n[i];
            if(sum%2==1)
            {
                printf("Collection #%d:
    Can't be divided.
    
    ",cas);
                continue;
            }
    
            v=sum/2;
            memset(dp,0,sizeof(dp));
            for(int i=0;i<6;i++)
                mp(i+1,i+1,n[i]);
            if(dp[v]==sum-v)
                printf("Collection #%d:
    Can be divided.
    
    ",cas);
            else printf("Collection #%d:
    Can't be divided.
    
    ",cas);
        }
        return 0;
    }
  • 相关阅读:
    编译资源收集
    volatile和synchronized到底啥区别?多图文讲解告诉你
    沙雕与大婶 | Mock掉你的外部依赖吧
    全网最详细的一篇Flutter 尺寸限制类容器总结
    一篇带你看懂Flutter叠加组件Stack
    【MySQL】:事务四大特性与隔离级别
    Dubbo 入门-细说分布式与集群
    Java 线程基础知识
    SpringBoot图文教程9—SpringBoot 导入导出 Excel 「Apache Poi」
    搭建博客、自己的小窝?快来看看这些开源静态网站生成器
  • 原文地址:https://www.cnblogs.com/atmacmer/p/5366389.html
Copyright © 2011-2022 走看看