nyoj30 Gone Fishing

原题: http://acm.nyist.net/JudgeOnline/problem.php?pid=30

//nyoj 30
//题目大意:John想去钓鱼,但是他只有h个小时的时间。已知有n个池塘,每个池塘的初始鱼数量为fi,在某个池塘钓一次鱼(每次钓鱼耗时固定为5分钟),这个池塘的鱼的数量就会减少di,如果这个池塘鱼数fi<=di,则下一次将不会有鱼在池塘中
//         每两个池塘之间都有距离,从池塘i走到i+1需要花费ti个单元的时间(每个单元为5分钟,即耗时 ti*5min),John可以在任何一个位置停止钓鱼,但他只能从一个池塘走到下一个池塘,不能返回
//         如果John在钓完鱼之后还有剩余的时间,则把时间加在第一个池塘的用时上面
//        问John在有限的时间内最多可以钓多少数量sum的鱼, 如果有些方案的sum相同,则比较第一个池塘的用时,哪个用时长选择哪个方案,如果第一个池塘用时也相同,就比较第二个池塘用时长的方案..... 
//思路:分别计算停留在每一个池塘的情况,在每一种情况中使用贪心,即每次去鱼量最大的池塘钓鱼,详细过程: 
//     池塘数量最多只有25个,所以我们可以分别计算出John在不同的池塘停止钓鱼的最大钓鱼数
//     ①假设John在第一个池塘停止钓鱼,那我们就计算 全部时间h 用在第一个池塘钓鱼的结果
//     ②假设John在第二个池塘停止钓鱼,那我们要先把时间h 减去第1个和第2个池塘之间的时间,然后剩下的时间去钓鱼,怎么钓呢,当然是每次都选择鱼数量多的那个池塘去钓鱼,直到时间为0,或者池塘都没有鱼了即停止
//      然后比较①和②的鱼数.....选择最大的那个方案 
//     ③假设John在第三个池塘停止钓鱼,则我们要减去第1个和第2个,第2个和第3个池塘之间的时间,然后剩下的时间去钓鱼,重复上面的过程 
//这题没解出来,看了别人的解题报告才明白
//因为我一开始觉得好复杂,题目都看了很久,然后卡在池塘之间的时间间隔,想不出 如果选择到底过不过去下一个池塘? 
//解题报告说 分别枚举停留在每一个池塘的情况,在每一种情况中使用贪心,去鱼量最大的池塘钓鱼,我就恍然大悟了,题目最多只有25个池塘, 所以枚举是没有问题的。 
//这题我觉得后台的数据还是比较松的,没有当钓鱼数相同,要比较第一个池塘用时长的情况。 
//我觉得这是一道很难的题,也是一道很好的题,这种思路值得学习。 
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<memory.h>
using namespace std;
struct Lake
{
	int pos;
	int fi;
	int di;
}lake[26]; //池塘 
int ti[26];//池塘间隔时间 
int rs[26][26];//存放每个池塘花费时间 
struct cmp
{
	bool operator ()(Lake a,Lake b)
	{
		if(a.fi!=b.fi)
		{
			return a.fi<b.fi;	//鱼量大的池塘优先	
		}else{
			return a.pos>b.pos;//位置前的池塘优先 
		}
	}	
};
int main()
{
	int n;
	scanf("%d",&n);
	while(n!=0)
	{
		int h;
		int rspos=0;
		scanf("%d",&h);
		h=h*12;//可用时间 
		for(int i=0;i<n;i++)
		{
			lake[i].pos=i;
			scanf("%d",&lake[i].fi);
		}
		for(int i=0;i<n;i++)
		{
			scanf("%d",&lake[i].di);
		}
		for(int i=0;i<n-1;i++)
		{
			scanf("%d",&ti[i]);
		}
		memset(rs,0,sizeof(rs));
		int sum=0;
		int hh=h;
		int ai=lake[0].fi;
		int di=lake[0].di;
		while(hh>0) //在第一个池塘捕鱼 
		{
			hh--;
			sum=sum+ai;
			ai=ai-di;
			if(ai<=0){
				break;
			}
		}
		rs[0][0]=h;
		for(int i=1;i<n;i++)//以不同的湖为终点 
		{
			h=h-ti[i-1];//剩下的捕鱼时间
			priority_queue<Lake,vector<Lake>,cmp>q1;
			for(int j=0;j<=i;j++)
			{
				q1.push(lake[j]);
			} 
			int hh=h;
			int tmp=0;
			while(hh>0 && q1.size()) //在鱼量最多的池塘钓鱼 
			{
				hh--;
				Lake now=q1.top();
				q1.pop();
				tmp=tmp+now.fi;
				rs[i][now.pos]++;//捕鱼时间增加 
				now.fi=now.fi-now.di;
				if(now.fi>0)
				{
					q1.push(now);	
				}
			}
			if(hh>0)//如果时间还有剩,加到第一个池塘上面去 
			{
				rs[i][0]+=hh;
			} 
			if(tmp>sum) //如果这个方案钓鱼数更多 
			{
				rspos=i;
				sum=tmp;
			}
		}
		printf("%d",rs[rspos][0]*5);
		for(int i=1;i<n;i++) //输出每个池塘的用时 
		{
			printf(", %d",rs[rspos][i]*5);
		}
		printf("\nNumber of fish expected: %d\n\n",sum);//输出最大钓鱼数 
		scanf("%d",&n);
	}	
	return 0;
}         


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值