POJ 1042 Gone Fishing (贪心)

题目大意:

一个人要去钓鱼,可用时间为h(小时),可选湖泊为n个,可以将湖泊看成在一条直线上的顺序的n个点,要去第k个点必须从第k-1个点出发,所用时间为t[k-1](个5分钟),每个湖初始鱼的数目为f[i](注意,可能为0),每个湖泊单位时间(五分钟)鱼的数目减少d[i]条(这是人在该湖泊钓鱼的情况下,人不在就不会减少),问h时间内他能钓的鱼最多是多少?

题目分析:

贪心策略,先找到他能到达的最远的(所有时间用来跑路的极限值)湖泊p,然后分为若干种情况:他的活动范围是  1~1  、  1~2 、 ·······  1~p,即他可以选择的跑去钓鱼的最远的湖泊有p个,枚举每种情况,把总时间减去跑路的时间就是他能钓鱼的时间,在情况  1~k 时,对于每一个单位时间(五分钟),都从1到k枚举每个湖泊找到最大值记录相应位置,然后每种情况都算一次,迭代出最大值就可以了。

/*
poj  1042
236K	47MS
*/

#include<cstdio>
#include<cstring>
#include<iostream>

#define MAXN 30

using namespace std;

int f[MAXN],d[MAXN],t[MAXN],n,ans[MAXN],tot[MAXN][200],h;
//tot[i][j]是第i个在湖第j个5分钟能抓的鱼的数目 

void init()
{
	h *= 12;
	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;i ++)
		scanf("%d",&t[i]);
	for(int i = 1;i <= n;i ++)
		for(int j = 1;j <= h;j ++)
			tot[i][j] = max(f[i] - d[i] * (j - 1) , 0);
}

void calc()
{
	int far = 1,tmp[MAXN] = {0},index[MAXN] = {0},sum = -0xfffffff;//可能有全为零的情况 
	//far为其能到达并钓一会鱼的最远的湖,tmp[i]是从i出发到达下一个湖时用的跑路总时间 
	//index[i]是指为钓到最多的鱼在第i个湖待的时间 
	while(far <= n)//计算所能到达的最远的湖 
	{
		tmp[far] = tmp[far-1] + t[far];
		if(tmp[far] >= h)
			break;
		far++;
	}
	if(far > n)
		far = n;
	int cnt = 1;
	while(cnt <= far)//从近到远试遍所有情况 
	{
		int tsum = 0;
		memset(index , 0 , sizeof(index));
		int th = h - tmp[cnt-1];//可用钓鱼时间
		for(int i = 1;i <= th;i ++)//对于每一个单位时间(五分钟)都寻找最多鱼的湖 
		{
			int tmax = 0,tj = 1;//默认为第一个湖 
			for(int j = 1;j <= cnt;j ++)//最远到第cnt个湖  cnt∈[1,far] 
			{
				if(tot[j][index[j]+1] > tmax)
				{
					tj = j;//记录位置 
					tmax = tot[j][index[j]+1];//记录数目 
				}
			}
			tsum += tmax;
			index[tj] ++;//在第tj个湖已经待的时间+1 
		}
		if(tsum > sum)//替换 
		{
			sum = tsum;
			memcpy(ans , index , sizeof(index));
		}
		cnt ++;//范围扩大一个湖 
	}
	for(int i = 1;i <= n;i ++)
	{
		if(i == n)
			printf("%d\n",ans[i] * 5);
		else
			printf("%d, ",ans[i] * 5);
	}
	printf("Number of fish expected: %d\n\n",sum);
}

int main()
{
	freopen("./1042.in" , "r" , stdin);
	while(cin>>n>>h)
	{
		init();
		calc();
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值