鱼塘钓鱼

N N N 个鱼塘排成一排,每个鱼塘中有一定数量的鱼,例如: N = 5 N=5 N=5 时,如下表:

鱼塘编号12345
第1分钟能钓到的鱼的数量(1…1000)101420169
每钓鱼1分钟钓鱼数的减少量(1…100)24653
当前鱼塘到下一个相邻鱼塘需要的时间(单位:分钟)3544

即:在第 1 1 1 个鱼塘中钓鱼第 1 1 1 分钟内可钓到 10 10 10 条鱼,第 2 2 2 分钟内只能钓到 8 8 8 条鱼,……,第 5 5 5 分钟以后再也钓不到鱼了。

从第 1 1 1 个鱼塘到第 2 2 2 个鱼塘需要 3 3 3 分钟,从第 2 2 2 个鱼塘到第 3 3 3 个鱼塘需要 5 分钟,……

给出一个截止时间 T T T,设计一个钓鱼方案,从第 1 1 1 个鱼塘出发,希望能钓到最多的鱼。

假设能钓到鱼的数量仅和已钓鱼的次数有关,且每次钓鱼的时间都是整数分钟。

输入格式
5 5 5 行,分别表示:

1 1 1 行为 N;

2 2 2 行为第 1 1 1 分钟各个鱼塘能钓到的鱼的数量,每个数据之间用一空格隔开;

3 3 3 行为每过 1 1 1 分钟各个鱼塘钓鱼数的减少量,每个数据之间用一空格隔开;

4 4 4 行为当前鱼塘到下一个相邻鱼塘需要的时间;

5 5 5 行为截止时间 T T T

输出格式
一个整数(不超过 2 31 − 1 2^{31}−1 2311),表示你的方案能钓到的最多的鱼。

数据范围
1 ≤ N ≤ 100 , 1 ≤ T ≤ 1000 1≤N≤100,\\ 1≤T≤1000 1N100,1T1000
输入样例:

5
10 14 20 16 9
2 4 6 5 3
3 5 4 4
14

输出样例:

76
  1. 思路
    枚举
    我是看了刘汝佳的书,其实我一直没想明白,为什么用贪心,如何用,心里面一直都不清楚。
    仔细想了才清楚。因为每次钓鱼只能选择左半段进行活动。那么枚举左半段即可。
    第一次枚举:只能在 1 , 1, 1池塘里面钓鱼。
    第二次枚举:只能在 1 , 2 1,2 12池塘里面钓鱼。
    第三次枚举:只能在 1 , 2 , 3 1,2,3 123池塘里面钓鱼。
    第i次枚举:只能在 1 , 2 , 3 ,     i 1,2,3,~~~i 1,2,3,   i池塘里面钓鱼。
    直到最后一个池塘。
    贪心
    对于每一次枚举用贪心算法。由于对于第 i i i次枚举,对于所有的枚举到的池塘 ( 1 (1 (1~ i ) i) i)来说,都是要路过的。并且都是从左至右的方式进行路过。
    那么跑路的时间就是恒定的。余下的时间直接用来钓鱼。去掉了跑路的时间,题又简单了一半。
    接下来看怎么贪心。
    这里有个很大的限制是,钓鱼是必须从左边的池塘向右边的池塘一个接一个地钓鱼。
    首先我们想一下如果不是一个接一个地钓鱼会是什么结果。
    我们每次都是选择鱼最多的来钓。其实结果都是一样的。
    比如
    第一次我们选择在 1 1 1号池塘钓鱼。 t 1 t1 t1
    第二次我们选择在 2 2 2号池塘钓鱼。 t 2 t2 t2
    第三次我们又选择在 1 1 1号池塘钓鱼。 t 3 t3 t3

    第一次我们在 1 1 1号池塘钓鱼用了 t 1 + t 3 t1+t3 t1+t3时间
    第二次我们走到 2 2 2号池塘钓鱼用了 t 2 t2 t2时间。
    效果是一样的。钓鱼的数量是一样的。
    所以贪心的策略就是每次钓鱼的时候选择鱼最多的来钓鱼。(这里可以用一个最大堆来做)
#include <bits/stdc++.h>

using namespace std;
typedef pair<int,int> pii;
const int inf = 0x3f3f3f3f;
const int maxn = 110;
priority_queue<pii> q;
int f[maxn], d[maxn], t[maxn];
int n;
int T;

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &f[i]);
    }
    for (int i = 1; i <= n; i++) {
        scanf("%d", &d[i]);
    }
    for (int i = 1; i <n; i++) {
        scanf("%d", &t[i]);
    }
    scanf("%d", &T);
    int mx = -inf;
    int walk_time = 0;
    for (int k = 1; k <= n; k++) {
        int rest_time = T - walk_time;
        int ans = 0;
        while (!q.empty()) q.pop();
        for (int i = 1; i <= k; i++) {
            q.push({f[i], i});
        }
        while (rest_time > 0 && q.top().first > 0) {
            pii p = q.top();
            q.pop();
            ans += p.first;
            p.first -= d[p.second];
            q.push(p);
            rest_time--;
        }
        mx = max(ans, mx);
        walk_time += t[k];
    }
    printf("%d\n", mx);
    return 0;
}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值