grass 剪草

【题目描述】
有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是 O(n3) O ( n 3 ) 的算法,但我们可以利用决策的单调性化简为 O(n2) O ( n 2 ) 。同时我们还可以用滚动数组优化空间复杂度。由于这道题目太水,所以都不需要。

#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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值