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\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道的更多相关文章
- Coins HDU - 2844 POJ - 1742
Coins HDU - 2844 POJ - 1742 多重背包可行性 当做一般多重背包,二进制优化 #include<cstdio> #include<cstring> in ...
- 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 ...
- 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 ...
- hdu 2844 poj 1742 Coins
hdu 2844 poj 1742 Coins 题目相同,但是时限不同,原本上面的多重背包我初始化为0,f[0] = 1;用位或进行优化,f[i]=1表示可以兑成i,0表示不能. 在poj上运行时间正 ...
- 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 ...
- 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 ...
- 扫描线三巨头 hdu1928&&hdu 1255 && hdu 1542 [POJ 1151]
学习链接:http://blog.csdn.net/lwt36/article/details/48908031 学习扫描线主要学习的是一种扫描的思想,后期可以求解很多问题. 扫描线求矩形周长并 hd ...
- hdu 1540/POJ 2892 Tunnel Warfare 【线段树区间合并】
Tunnel Warfare Time Limit: 4000/2000 MS ...
- HDU 3966 & POJ 3237 & HYSBZ 2243 树链剖分
树链剖分是一个很固定的套路 一般用来解决树上两点之间的路径更改与查询 思想是将一棵树分成不想交的几条链 并且由于dfs的顺序性 给每条链上的点或边标的号必定是连着的 那么每两个点之间的路径都可以拆成几 ...
随机推荐
- String.split()分割字符串
string.split(s[, sep[, maxsplit]]) Return a list of the words of the string s. If the optional secon ...
- C++类继承中,基类/当前对象属性/当前对象的构造顺序
[1]中提到,规范的派生类构造函数三个要点: 首先创建基类对象 应通过成员初始化列表,创建基类对象 应该初始化本派生类新增的成员变量 那在构造派生类实例的过程中,其基类(以及多继承的时候多个基类)/当 ...
- Xcode插件推荐
deriveddata-exterminator: A magic button in Xcode to exterminate the current project's DerivedData d ...
- CodeForces 709C Letters Cyclic Shift
贪心. 肯定是两个$a$之间的那些字符都$-1$,没有$a$就全部$-1$.如果输入的串全是$a$,那么把最后一个$a$改成$z$. #pragma comment(linker, "/ST ...
- hdu1029
#include<iostream>#include<string.h>using namespace std;int main(){ int n,i; int t; int ...
- Office下载地址
文件名cn_office_professional_plus_2016_x86_x64_dvd_6969182.isoSHA1277926A41B472EE38CA0B36ED8F2696356DCC ...
- 让IE6 IE7 IE8 IE9 IE10 IE11支持Bootstrap的解决方法 转载
最近做一个Web网站,之前一直觉得bootstrap非常好,这次使用了bootstrap3,在chrome,firefox,safari,opera,360浏览器(极速模式).搜狗浏览器等浏览器下均没 ...
- 多线程随笔一(AutoResetEvent和ManulResetEvent)
AutoResetEvent和ManulResetEvent是.net中用来做线程的同步的两个类.从类名上不难看出,这两个类的区别在于一个是自动的,一个是手动的(这不是废话嘛).两个类的实现原理大致相 ...
- xml文件查找重复元素(超简单版)
使用WPS,新建一个表格文件,将xml拖入表格,点数据,选中存在重复项的列,点高亮重复项,OK.
- escape,encodeURI,encodeURIComponent
JavaScript/js中,有三个可以对字符串编码的函数,分别是: escape,encodeURI,encodeURIComponent,相应3个解码函数:unescape,decodeURI,d ...