题目转自:
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#include #include #include #include #include using namespace std;vector 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 >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
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#include #include 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 =0;i--) { if(dp[i-a[k].cost]*a[k].per
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#include #include #include 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 =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\n",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#include #include #include 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
5.poj 2392 Space Elevator
哈哈哈哈哈哈可以叫堆塔吗这题
有k种塔,分别给出每种塔的高度h和数目c,以及限制高度a(往上堆某种塔的时候不能超过它对应的a),问最多能堆多高?
这题用多重背包解,一开始把quantity看成quality还想说给我质量干嘛。。还打算用完全背包来着。。。
这题的数据得排下序,根据a的大小排升序,讲道理的话,a小的不就得先把它给堆了嘛。
重点!想当然的以为dp[最大的a]就是最大值了,其实不是啊。。所以还得遍历一遍dp来找最大值。。。不然就wa了
#include#include #include #include 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
6.poj 1276 Cash Machine
道理跟上一题一样的,直接贴代码了,比上一题还简单,不用排序了,limit只有一个总的。
#include#include #include #include 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
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#include #include #include 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 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]
8.hdu 1059 Dividing
因为要判断能不能平分,所以sum如果为奇数就不行,否则,用多重背包(因为每种球都给了number数),容量v为sum的一半,然后看dp[v]是否等于另一半sum-v。
#include#include #include #include 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