Gone Fishing

有n(2<=n<=25)个湖从左到右一字排开。从第i个湖走到第i+1个湖要耗时t[i]个时间片(每个时间片5分钟)。
John有h(1<=h<=16)个小时可以用在这些湖钓鱼(包括湖间行走时间)。在每个湖待的时间必须是整数个时间片或0。就算钓不着鱼了,也可以在湖边呆着。
对于湖i,John在那里的第一个时间片可以钓到鱼f[i]条,且后续的每个时间片,能钓到的鱼数量都比上一个时间片少d[i]。
注意John只能从第一个湖出发,从左往右走,不能回头。最后John要停在哪里都可以。问John最多能钓多少条鱼。

**输入:
每个测试用例,首先给出池塘数n,然后是时间h(小时为单位),接下来的两行分别有n个整数,分别表示f[i]和d[i],接下来的一行为n-1个整数,表示t[i]。n为0时表示输入结束。
输出:
对于每个测试用例,第一行依次输出在每个池塘的停留时间(分钟为单位),每个时间之间用逗号+空格分开。第二行输出能钓到的最多的鱼的数量
**
Sample Input

2 
1 
10 1 
2 5 
2 
4 
4 
10 15 20 17 
0 3 4 3 
1 2 3 
4 
4 
10 15 50 30
 0 3 4 3 
1 2 3
 0 

Sample Output

45, 5
 Number of fish expected: 31 
240, 0, 0, 0
 Number of fish expected: 480 
115, 10, 50, 35 
Number of fish expected: 724 

这道题用的知识点是贪心、还有优先队列。
难点:
走路时间可多可少,不知道到底该花多长时间纯钓鱼才最好
解决:
枚举最终停下来的湖,将方案分成n类。每类方案的走路时间就是确定的。在每类方案里找最优解,然后再优中选优。终点是i
钓鱼时间=总时间-走路时间
钓鱼时间:钓鱼次数确定,每次都从f数组中找最大值。
如何找最大值。使用一个优先队列

优先队列的存储:
在这里插入图片描述

代码实现如下:

#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
int n, h, t[100010], fis[100010],time1[100010],d[100010];
typedef struct node
{
	int fish, id, tim;//fish表示可以钓的鱼数,id表示当前的池塘号,tim表示停留时间。
	bool operator < (const node & a)const
	{
		return fish == a.fish ? id > a.id:fish < a.fish;
	}
	//这个结构的意思是,定义的这三个量<a中的三个量。
	//假如这两个的fish相等,就返回id小的的那个作为大的(题目要求);
	//否则,就返回fish大的那个。
}node;
void solve()
{
	int maxn = -10000;
	int num;
	for (int i = 0; i < n; i++)
	{// 从第一个池塘开始枚举        
		priority_queue<node> q;//默认最大值在顶端,即树根,是按完全二叉树存的。
		int time = h * 60;//输入的时间是小时,要转换成分钟。
		time -= t[i] * 5; // 减去路程上花的时间            
		for (int j = 0; j <= i; j++)
		{//将枚举的池塘以此压入队列中            
			node next;
			next.fish = fis[j];
			next.id = j;// 方便最后输出和排序           
			next.tim = 0;
			q.push(next);
		}
		int sum = 0;
		while (time > 0)
		{
			//在规定的时间内,吊枚举的池塘的鱼求出最大值,并求出来每个池塘的时间           
			node next = q.top();
			q.pop();
			sum += next.fish;
			next.tim += 5;
			time -= 5;
			if (next.fish) next.fish -= d[next.id];
			if (next.fish < 0) next.fish = 0;
			q.push(next);
		}
		if (sum > maxn)
		{//判断是否是最大的            
			maxn = sum;
			num = i;//记录到哪个池塘鱼最多,之后的鱼塘停留的时间就是0; 
			while (!q.empty())
			{
				node next = q.top();
				q.pop();
				time1[next.id] = next.tim;
			}
		}
	}
	for (int i = 0; i <= num; i++)
	{
		if (i == 0) printf("%d", time1[i]);
		else printf(", %d", time1[i]);
	}
	for (int i = num + 1; i < n; i++)
	{
		printf(", 0");
	}
	cout << endl;
	printf("Number of fish expected: %d\n", maxn);
}
int main()
{
	while (scanf("%d", &n) && n)
	{
		scanf("%d", &h);
		for (int i = 0; i < n; i++)
		{
			cin >> fis[i];//表示池塘鱼数
		}
		for (int i = 0; i < n; i++)
		{
			cin >> d[i];//表示钓过一次,减少多少鱼
		}
		t[0] = 0;
		for (int i = 1; i < n; i++)
		{
			int x;
			cin >> x;
			t[i] = t[i - 1] + x;//这样储存的话就是到下标池塘的所需时间
		}
		solve();
	}
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值