【题解】钓鱼

题目来源:loj

题目描述

在一条水平路边,有n(2≤n≤100)个钓鱼湖,从左到右编号为1、2、3、…、n。佳佳有H(1≤H≤20)个小时的空余时间,他希望用这些时间钓到尽量多的鱼。他从湖1出发,向右走,有选择的在一些湖边停留一定的时间钓鱼,最后在某一个湖边结束钓鱼。佳佳测出从第i个湖到第i+1个湖需要走5×Ti分钟的路,还测出在第i个湖边停留,第一个5分钟可以钓到鱼Fi,以后再每钓5分钟鱼,鱼量减少Di。为了简化问题,佳佳假定没有其他人钓鱼,也不会有其他因素影响他钓到期望数量的鱼。请设计一个算法求出佳佳能钓到最多鱼的方案。

输入

输入的第一行为湖泊的数量n

第二行为钓鱼的可用时间数,以小时记

第三行为n个整数,表示第i个湖泊第一个5分钟的钓鱼数量

第四行为n个整数,表示第i个湖泊再钓鱼5分钟的鱼量减小值p

第五行为n-1个整数,表示从第i个湖泊到第i+1个湖泊所需要的时间数5*Ti分钟

输出

输出最大的钓鱼数量,每个输出占一行

样例输入

3
1
4 5 6
1 2 1
1 2

样例输出

35

思路

贪心+priority_queue
枚举结束的鱼塘编号 i ,然后算出除去在路上花的时间,剩下的就是可以钓鱼的时间,怎么安排?如果是我钓鱼,肯定是先选择鱼的数量最多的那个鱼塘(因为目前那个鱼塘可以钓最多的鱼),假设它为 j ,钓完鱼塘 j 后,鱼塘 j 的鱼的数量会减少,那鱼塘 j可能就不是目前鱼的数量最多的鱼塘了,我就选下一个目前鱼的数量最多的鱼塘
可是这个亚子在路上来来回回不是会很耗费时间吗?

以下的解释来自洛谷的一位博主

怎样解决这个问题呢?

我们可以先确定可以走到的最远的鱼塘i,然后把时间减去从鱼塘1走到鱼塘i的时间,在剩下的时间里一直钓鱼,可以假设钓鱼人可以瞬间移动,在鱼塘1到鱼塘i之间采用上面的贪心方法,就可以求到最远走到鱼塘i的最优解。

为什么可以假设钓鱼人可以瞬间移动呢?

因为钓鱼人的钓鱼的范围是从鱼塘1到鱼塘i,所以他花的最少的移动时间就是从鱼塘1到鱼塘i的时间,那么剩下来的时间就可以全部用来钓鱼,那么这时我们要考虑的并不是钓鱼的次序,而是钓了哪几次鱼,也就是说,我们只要知道每次钓的鱼是在哪里钓的就行了,并不要知道从鱼塘1出发之后的钓鱼过程,而上面提到的贪心算法,恰恰求的就是每次钓的鱼是在哪里钓的。

code

#include<bits/stdc++.h>
using namespace std;
const int N=110;
int n,h,t[N],reduce[N],anss;
struct node{
    
    
	int num,id; //num:鱼的数量  id:鱼塘编号 
	bool operator <(node x) const{
    
     //自定义的重载运算符 
		return x.num>num; //规定鱼的数量num大的在前 
	}
}a[N];
int main()
{
    
    
	scanf("%d%d",&n,&h);
	h*=12; //有多少个时间段可以用 
	for (int i=1;i<=n;i++) 
	{
    
    
		scanf("%d",&a[i].num);
		a[i].id=i;
	}
	for (int i=1;i<=n;i++) scanf("%d",&reduce[i]); //每钓一次减少的鱼的数量 
	for (int i=2;i<=n;i++) scanf("%d",&t[i]);  //在路上走的时间
	for (int i=1;i<=n;i++)
	{
    
    
		int cnt=0;
		h-=t[i];
		priority_queue <node> q;
		for (int j=1;j<=i;j++) q.push(a[j]);
	    for (int j=1;j<=h;j++)
		{
    
    
			node now=q.top();
			if (now.num>0) //如果当前有鱼可以钓 
			{
    
    
				cnt+=now.num;//钓鱼 
				now.num-=reduce[now.id]; //鱼的数量减少 
				q.pop();
				q.push(now); //更新队列 
			}
		} 
		anss=max(anss,cnt); //更新答案 
	}
	printf("%d\n",anss);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_45485187/article/details/102895091