当前位置:网络安全 > 【题解】钓鱼

【题解】钓鱼

  • 发布:2023-09-28 17:22

题目来源: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
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;
}

相关文章