您的位置:首页 > 其它

动态规划练习1

2017-07-25 14:15 162 查看
题目描述:

在ls森林里有一只很能砍树的樵夫lw,他左手扛狂暴药水,右手握着雷神之斧,白天砍树,晚上喝狂暴药水。这天他接到了国王给他的一个任务:砍掉两颗树。设两颗树的耐久值都为x(各自独立)。而lw有n(n<=100)把不同的斧头,设第i把斧头每a[i]秒种能消耗第一棵树1点耐久值,或者每b[i]秒消耗第二棵树1点耐久值。对于一个斧头来说,砍树对象可以变换,即可以砍a[i]秒a,再砍b[i]秒b。对于一棵树来说,可以同时被多个斧头砍。当两颗树的耐久值都小于等于0时任务完成。lw想问你完成的最短时间是多少。

输入格式:

第一行两个数,分别为n和x,即斧头数和树的耐久值,接下来n行每行两个数,第i+1行的两个数为a[i]和b[i]。

输出格式:

第一行一个数t,即完成任务的最少时间。

样例输入:tree.in

2 20

5 1

1 5

样例输出:tree.out

20

数据范围:

对于30%的数据,n<=10,x<=30,a[i],b[i]<=20。

对于100%的数据,n<=100,x<=100,a[i],b[i]<=100。

[b]题解:[/b]

[b]考虑f[i][j]表示前i个斧头砍1的j块,还可以砍2的最多块数。[/b]

[b]d[i][0]存砍1的效率,d[i][1]存砍2的效率[/b]

[b]f[i][j]=max(f[i][j],f[i-1][j-k]+(day-d[i][0]*k)/d[i][1]);[/b]

[b]f[i-1,j-k]是前i-1个斧头砍j-k个1还能砍几个2。day-d[i,0]*k是第i个斧头砍k个1还剩的时间[/b]

[b](day-d[i][0]*k)/d[i][1]第i个斧头还能砍几个2[/b]

[b]所以f[i-1][j-k]+(mid-d[i][0]*k)/d[i][1]是前i个斧头一共可以砍几个2[/b]

[b]显然是成立的。[/b]

[b]而对于day的值,可以证明,f是随day单调递增的。我们可以二分这个day值,每次用DP检验。若f
[x]>=x,r=mid-1;f
[x]<x,l=mid+1。
[/b]

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int f[101][101],n,x,a[101],b[101];
int gi()
{
int ans=0,f=1;
char i=getchar();
while(i<'0'||i>'9'){if(i=='-')f=-1;i=getchar();}
while(i>='0'&&i<='9'){ans=ans*10+i-'0';i=getchar();}
return ans*f;
}
bool judge(int mid)
{
int i,j,k;
memset(f,200,sizeof(f));
f[0][0]=0;
for(i=1;i<=n;i++)
for(j=0;j<=x;j++)
for(k=0;k<=min(j,mid/a[i]);k++)
f[i][j]=max(f[i][j],f[i-1][j-k]+(mid-k*a[i])/b[i]);
return f
[x]>=x;
}
int main()
{
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
int i,j;
n=gi();x=gi();
for(i=1;i<=n;i++){a[i]=gi();b[i]=gi();}
int l=0,r=20000,ans=0;
while(l<=r)
{
int m=(l+r)>>1;
if(judge(m))ans=m,r=m-1;
else l=m+1;
}
printf("%d",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: