建议全屏阅读
这道题可以用 贪心 + 大根堆 来解决。
先把题目放上来。
描述
有N个鱼塘排成一排(N<100),每个鱼塘中有一定数量的鱼,例如:N=5时,如下表:
鱼塘编号 1 2 3 4 5
每1分钟能钓到的鱼的数量(1..1000) 10 14 20 16 9
每1分钟能钓鱼数的减少量(1..100) 2 4 6 5 3
当前鱼塘到下一个相邻鱼塘需要的时间(单位:分钟)3 5 4 4
即:在第1个鱼塘中钓鱼第1分钟内可钓到10条鱼,第2分钟内只能钓到8条鱼,……,第5分钟以后再也钓不到鱼了。从第1个鱼塘到第2个鱼塘需要3分钟,从第2个鱼塘到第3个鱼塘需要5分钟,……
给出一个截止时间T(T<1000),设计一个钓鱼方案,从第1个鱼塘出发,希望能钓到最多的鱼。
假设能钓到鱼的数量仅和已钓鱼的次数有关,且每次钓鱼的时间都是整数分钟。
输入格式
共5行,分别表示:
第1行为N;
第2行为第1分钟各个鱼塘能钓到的鱼的数量,每个数据之间用一空格隔开;
第3行为每过1分钟各个鱼塘钓鱼数的减少量,每个数据之间用一空格隔开;
第4行为当前鱼塘到下一个相邻鱼塘需要的时间;
第5行为截止时间T。
输出格式
一个整数(不超过2^31−1),表示你的方案能钓到的最多的鱼。
这道题我们可以先想一下贪心思路:
首先我们知道:
- 每一个鱼池可能要钓鱼
- 假如我们走到了鱼池 k ,那么不会到 k 前面的鱼池去钓鱼,因为要在前面钓的话,就在来 k 之前钓完了,折回去明显是在浪费时间
所以我们可以先枚举只走到鱼池 k 而不去后面的鱼池能钓到的最多的鱼。我就在代码上面讲吧。
#include <cstdio>
#include <cmath>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 105;
struct node{
int fish;
int lake;
}Heap[MAXN], a, len;//定义一个结构体,第一个是钓到的鱼的数量,第二个是鱼池的编号
int t[MAXN], f[MAXN], d[MAXN];//分别为从 i 鱼池到 i + 1 鱼池的时间,在 i 鱼池最开始每分钟能钓到的鱼的数量,在 i 鱼池每一分钟减少的鱼的数量
/*void maintain(int x, int len) {
int son = x * 2;
while (x * 2 <= len) {
if (son < len && Heap[son].fish < Heap[son + 1].fish) son++;
else if (Heap[x].fish > Heap[son].fish) break;
swap(Heap[x], Heap[son]);
x = son;
}
}*/
//这是一个错误的维护大根堆的方式,至于哪里错了,读者可以自行尝试查找(我一开始是这样写的)
void maintain(int i, int k) {// maintain意为保持,维护(建议从主函数里面的循环开始阅读)
node a;//定义一个结构体,后面有用
int next;//左儿子的编号
a = Heap[i];//先把这里保存下来,后面会把Heap[i]改变
next = i * 2;//左儿子的编号是他父亲的两倍,此处不再赘述
while (next <= k) {//他的左儿子一定要不超出大根堆的长度
if (next < k && Heap[next].fish < Heap[next + 1].fish) next++;//他的右儿子存在并且比左儿子更优(生存能力更强),就在后面把Heap[i] = Heap[next]
if (a.fish < Heap[next].fish) {//原来的没有他的从左儿子和右儿子中选出来的优值更优,所以更新他
Heap[i] = Heap[next];//更新他
i = next;//继续往下查找,迭代
next *= 2;//继续往下查找,迭代
}
else break;//如果现在的值本来就是优,那就可以直接跳出(看不懂建议先做两道堆的模板题)
}
Heap[i] = a;//把他更新,此时的 Heap[i] 与原来的 Heap[i] 不同,可以自己思考
}
int main() {
int n, max_ = 0;//
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 - 1; i++) {
scanf("%d", &t[i]);
}
int m, t1 = 0;//t1为已经用掉的时间
scanf("%d", &m);//输入
for (int k = 1; k <= n; k++) {
int time = m - t1;//还剩下的时间
int ans = 0;//同于保存当前答案
for (int i = 1; i <= k; i++) {
Heap[i].fish = f[i];
Heap[i].lake = i;
} //初始化,更新数据,等会维护大根堆
for (int i = 1; i <= k/2; i++) {//其实可以是k, 这里为什么是 k / 2,就请读者自己思考
maintain(i, k);//维护大根堆,i 是当前位置,k 是大根堆长度
}
while ((time > 0) && (Heap[1].fish > 0)) {//时间是否用尽;还能否钓到鱼
ans += Heap[1].fish;//累加钓上来的鱼
Heap[1].fish -= d[Heap[1].lake];//每一分钟少的鱼
maintain(1, k);//继续维护大根堆,查找当前最优值
time--;//时间减少
}
max_ = max(max_, ans);//更新最终答案
t1 += t[k];//走到那里已经花的时间,累加
}
printf("%d", max_);//输出
return 0;//完美结束
}
博客就到这里了,有什么写得不好的还请指出
最后,还是感谢拜读!