题目转自: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\n",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%%\n",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\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<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\n",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\n",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\n",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!\n");
else printf("Good job,rabbit!\n");
}
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:\nCan't be divided.\n\n",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:\nCan be divided.\n\n",cas);
else printf("Collection #%d:\nCan't be divided.\n\n",cas);
}
return 0;
}

hdu和poj的基础dp30道的更多相关文章

  1. Coins HDU - 2844 POJ - 1742

    Coins HDU - 2844 POJ - 1742 多重背包可行性 当做一般多重背包,二进制优化 #include<cstdio> #include<cstring> in ...

  2. Eight hdu 1043 poj 1077

    Description The 15-puzzle has been around for over 100 years; even if you don't know it by that name ...

  3. HDU 3695 / POJ 3987 Computer Virus on Planet Pandora(AC自动机)(2010 Asia Fuzhou Regional Contest)

    Description Aliens on planet Pandora also write computer programs like us. Their programs only consi ...

  4. hdu 2844 poj 1742 Coins

    hdu 2844 poj 1742 Coins 题目相同,但是时限不同,原本上面的多重背包我初始化为0,f[0] = 1;用位或进行优化,f[i]=1表示可以兑成i,0表示不能. 在poj上运行时间正 ...

  5. HDU 3265/POJ 3832 Posters(扫描线+线段树)(2009 Asia Ningbo Regional)

    Description Ted has a new house with a huge window. In this big summer, Ted decides to decorate the ...

  6. HDU 2494/POJ 3930 Elevator(模拟)(2008 Asia Regional Beijing)

    Description Too worrying about the house price bubble, poor Mike sold his house and rent an apartmen ...

  7. 扫描线三巨头 hdu1928&&hdu 1255 && hdu 1542 [POJ 1151]

    学习链接:http://blog.csdn.net/lwt36/article/details/48908031 学习扫描线主要学习的是一种扫描的思想,后期可以求解很多问题. 扫描线求矩形周长并 hd ...

  8. hdu 1540/POJ 2892 Tunnel Warfare 【线段树区间合并】

    Tunnel Warfare                                                             Time Limit: 4000/2000 MS ...

  9. HDU 3966 & POJ 3237 & HYSBZ 2243 树链剖分

    树链剖分是一个很固定的套路 一般用来解决树上两点之间的路径更改与查询 思想是将一棵树分成不想交的几条链 并且由于dfs的顺序性 给每条链上的点或边标的号必定是连着的 那么每两个点之间的路径都可以拆成几 ...

随机推荐

  1. String.split()分割字符串

    string.split(s[, sep[, maxsplit]]) Return a list of the words of the string s. If the optional secon ...

  2. C++类继承中,基类/当前对象属性/当前对象的构造顺序

    [1]中提到,规范的派生类构造函数三个要点: 首先创建基类对象 应通过成员初始化列表,创建基类对象 应该初始化本派生类新增的成员变量 那在构造派生类实例的过程中,其基类(以及多继承的时候多个基类)/当 ...

  3. Xcode插件推荐

    deriveddata-exterminator: A magic button in Xcode to exterminate the current project's DerivedData d ...

  4. CodeForces 709C Letters Cyclic Shift

    贪心. 肯定是两个$a$之间的那些字符都$-1$,没有$a$就全部$-1$.如果输入的串全是$a$,那么把最后一个$a$改成$z$. #pragma comment(linker, "/ST ...

  5. hdu1029

    #include<iostream>#include<string.h>using namespace std;int main(){ int n,i; int t; int ...

  6. Office下载地址

    文件名cn_office_professional_plus_2016_x86_x64_dvd_6969182.isoSHA1277926A41B472EE38CA0B36ED8F2696356DCC ...

  7. 让IE6 IE7 IE8 IE9 IE10 IE11支持Bootstrap的解决方法 转载

    最近做一个Web网站,之前一直觉得bootstrap非常好,这次使用了bootstrap3,在chrome,firefox,safari,opera,360浏览器(极速模式).搜狗浏览器等浏览器下均没 ...

  8. 多线程随笔一(AutoResetEvent和ManulResetEvent)

    AutoResetEvent和ManulResetEvent是.net中用来做线程的同步的两个类.从类名上不难看出,这两个类的区别在于一个是自动的,一个是手动的(这不是废话嘛).两个类的实现原理大致相 ...

  9. xml文件查找重复元素(超简单版)

    使用WPS,新建一个表格文件,将xml拖入表格,点数据,选中存在重复项的列,点高亮重复项,OK.

  10. escape,encodeURI,encodeURIComponent

    JavaScript/js中,有三个可以对字符串编码的函数,分别是: escape,encodeURI,encodeURIComponent,相应3个解码函数:unescape,decodeURI,d ...