【题目描述】
有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,否则输出一个最早的完成时刻。
【输入格式】
第一行,两个整数N和H。 1 <= N <= 50,0 <= H <= 1000000。
第二行,N个整数,表示h[i]。0 <= h[i] <= 100000。
第三行,N个整数,表示grow[i]。1 <= grow[i] <= 100000。
【输出格式】
一个整数,最早完成时刻或-1。
【样例输入】
7 33
5 1 6 5 8 4 7
2 1 1 1 4 3 2
【样例输出】
5
【样例解释】
第1秒剪第2棵小草,第2秒剪第0棵小草,第3秒剪6棵小草,第4秒剪第5棵小草,第5秒剪第4棵小草。
如何判断不可行?如果一棵草被剪多次,只有最后一次是有效的。所以可以推广得,每棵草至多被剪一次。如果从1到n君不可行,则总体不可行。
选k棵要剪的草,最优的剪法一定是从生长率最低的草剪起,这样可以使得生长出来的高度最小。先将所有草关于生长率进行一次排序,然后就是经典dp。
这里dp是 的算法,但我们可以利用决策的单调性化简为 。同时我们还可以用滚动数组优化空间复杂度。由于这道题目太水,所以都不需要。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=60;
int n,H,sum;
int f[maxn][maxn];
struct node{
int h,g;
}a[maxn];
int cnt;
bool cmp(node x,node y){
return (x.g<y.g)||(x.g==y.g&&x.h<y.h);
}
int main(){
freopen("grass.in","r",stdin);
freopen("grass.out","w",stdout);
int T;
cin>>T;
while(T--){
cin>>n>>H;sum=0;
for(int i=1;i<=n;i++)
scanf("%d",&a[i].h),sum+=a[i].h;
for(int i=1;i<=n;i++)
scanf("%d",&a[i].g);
if(sum<=H){
printf("0\n");
continue;
}
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++)
sum+=a[i].g;
for(int i=1;i<=n;i++)
{
f[1][i]=sum-a[i].g-a[i].h;
if(f[1][i]<=H){
printf("1\n");
goto aaa;
}
}
sum=0;
for(int i=1;i<=n;i++)
sum+=a[i].g;
for(int t=2;t<=n;t++){
for(int i=1;i<=n;i++){
f[t][i]=1<<29;
for(int j=1;j<i;j++){
f[t][i]=min(f[t][i],f[t-1][j]+sum-a[i].h-a[i].g*t);
}
if(f[t][i]<=H){
printf("%d\n",t);
goto aaa;
}
}
}
printf("-1\n");
aaa:;
}
return 0;
}