这道题花了我超多时间!!!!
>Description
有N棵小草,编号0至N-1。奶牛Bessie不喜欢小草,所以Bessie要用剪刀剪草,目标是使得这N棵小草的高度总和不超过H。在第0时刻,第i棵小草的高度是h[i],接下来的每个整数时刻,会依次发生如下三个步骤:
(1)每棵小草都长高了,第i棵小草长高的高度是grow[i]。
(2)Bessie选择其中一棵小草并把它剪平,这棵小草高度变为0。注意:这棵小草并没有死掉,它下一秒还会生长的。
(3)Bessie计算一下这N棵小草的高度总和,如果不超过H,则完成任务,一切结束, 否则轮到下一时刻。
你的任务是计算:最早是第几时刻,奶牛Bessie能完成它的任务?如果第0时刻就可以完成就输出0,如果永远不可能完成,输出-1,否则输出一个最早的完成时刻。
>Input
第一行,两个整数N和H。 1 ≤ N ≤ 50,0 ≤ H ≤ 1000000。
第二行,N个整数,表示h[i]。0 ≤ h[i] ≤ 100000。
第三行,N个整数,表示grow[i]。1 ≤ grow[i] ≤ 100000。
>Output
一个整数,最早完成时刻或-1。
>解题思路
使用DP大法。f[i][j]表示的是前i棵草砍j次的最小高度和。
所以它有两种选择:
1第j次砍第i棵草(砍):f[i][j]=f[i-1][j-1]+tt[i]-a[i].g
//这里前i棵草中的每一棵都要生长一次,但是i已经被砍了,所以不用管i,直接把第i个清0
2第j次不砍第i棵草(不砍):f[i][j]=f[i-1][j]+a[i].yd+a[i].g*j
//由于第i棵草不砍,so这里的数是从f[i-1][j]过来的,前面的数(前i-1个数总共j次)都已经在之前处理过了,所以只用处理第i个数(加上第i个数的初始与生长总数)
=====================================================================================
a[i].yd为第i棵草的初始长度,g为生长速度。
tt为前i棵草的生长速度总和
>代码
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
struct ooo
{
int yd,g;
}a[55];
int n,s,f[55][55],ans,tt[55];
bool lil(ooo aa,ooo bb)
{
return aa.g<bb.g;
}
int main()
{
scanf("%d%d",&n,&s);
for(int i=1;i<=n;i++)
scanf("%d",&a[i].yd);
for(int i=1;i<=n;i++)
scanf("%d",&a[i].g);
sort(a+1,a+1+n,lil); //把结构体a按照g从小到大进行排序,先删去生长慢的,在删去生长快的
for(int i=1;i<=n;i++)
{
f[i][0]=f[i-1][0]+a[i].yd; tt[i]=tt[i-1]+a[i].g;
//在上文说明过
}
if(f[n][0]<=s)
{
printf("0");
return 0;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
f[i][j]=min(f[i-1][j]+a[i].yd+a[i].g*j,f[i-1][j-1]+tt[i]-a[i].g);
for(ans=1;ans<=n;ans++)
if(f[n][ans]<=s)
{
printf("%d",ans);
return 0;
}
printf("-1");
return 0;
}