鱼塘钓鱼题解(堆解决)

建议全屏阅读

这道题可以用 贪心 + 大根堆 来解决。
先把题目放上来。
描述

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

鱼塘编号 1 2 3 4 51分钟能钓到的鱼的数量(1..100010 14 20 16 91分钟能钓鱼数的减少量(1..1002 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^311),表示你的方案能钓到的最多的鱼。

这道题我们可以先想一下贪心思路:
首先我们知道:

  • 每一个鱼池可能要钓鱼
  • 假如我们走到了鱼池 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;//完美结束
}

博客就到这里了,有什么写得不好的还请指出
最后,还是感谢拜读!

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 书香水墨 设计师:CSDN官方博客 返回首页