• 鱼塘钓鱼题解(堆解决)


    建议全屏阅读

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

    有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;//完美结束
    }
    

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

  • 相关阅读:
    一道编程题: 在1~n之间选择若干个数,使其和为m
    关于raft算法
    程序员算法基础——动态规划
    c++中两个类互相引用的问题
    c++ 之模板进阶
    jmeter分布式操作-远程启动功能探索
    linux下安装不同版本的jdk
    Jmeter插件监控服务器性能
    测试开发面试-技术持续累积
    python:Jpype安装和使用
  • 原文地址:https://www.cnblogs.com/cqbzyanglin/p/13509288.html
Copyright © 2020-2023  润新知