题意解释:
John现有h个小时的空闲时间,他打算去钓鱼。钓鱼的地方共有n个湖,所有的湖沿着一条单向路顺序排列(John每在一个湖钓完鱼后,他只能走到下一个湖继续钓),John必须从1号湖开始钓起,但是他可以在任何一个湖结束他此次钓鱼的行程。
此题以5分钟作为单位时间,John在每个湖中每5分钟钓的鱼数随时间的增长而线性递减。每个湖中头5分钟可以钓到的鱼数用fi表示,每个湖中相邻5分钟钓鱼数的减少量用di表示,John从任意一个湖走到它下一个湖的时间用ti表示。
求一种方案,使得John在有限的h小时中可以钓到尽可能多的鱼。
贪心+枚举
题解:
我们可以把总时间分为两个部分:在路上的时间和在钓鱼的时间。由于路是单行的,所以在路上的时间取决于走的最远距离,即到达的池塘的最大编号。 剩余的时间用于钓鱼。我们可以把移动+钓鱼的混合过程拆分为移动的过程和钓鱼的过程,即指定一个池塘为终点,移动过程即从起点到终点的过程,钓鱼的过程就是从起点到终点的各个池塘中选择池塘钓鱼,因为移动过程所需的时间已经在前面考虑过了,这个时候我们就可以认为需要移动的时候可以直接瞬间到达。然后,选择到哪些池塘钓鱼的策略采用贪心的方法,每个钓鱼的5分钟都选择期望最大的那一个池塘,每在选择一个池塘钓鱼5分钟,减少相应池塘的期望,增加计划中在该池塘钓鱼的时间,然后继续选择期望最大的池塘,直到钓鱼的时间不够,或者池塘里没有鱼了。如果池塘没有鱼了,还有时间的话,把多余的时间分配给第一个池塘。
#include<stdio.h>
#include<string.h>
int n,h,flag;
int fi[50],di[50],ti[50];
int nu[50];//拷贝的数目
int sum[50][50];//sum[i][j]:到i池塘为止钓的鱼的数目
//j 表示所花的时间
void slove()
{
for(int i=1;i<=n;i++)
{
memset(nu,0,sizeof(nu));
for(int j=1;j<=i;j++)//拷贝
nu[j]=fi[j];
int stay=1;//钓鱼的位置
int maxn=1;//鱼数目的最大期望
int hour=h;
for(int j=1;j<i;j++)
hour-=ti[j];
while(hour>0&&stay<=i)
{
maxn=1;
for(int j=stay;j<=i;j++)//寻找最大值
if(nu[j]>nu[maxn])
maxn=j;
sum[i][0]+=nu[maxn];//更新已钓的鱼的个数
hour--;//减少时间
sum[i][maxn]++;//增加在这个池塘所待的时间
nu[maxn]-=di[maxn];//减少池塘的鱼的个数
if(nu[maxn]<0)
nu[maxn]=0;
for(int j=stay;j<=i;j++)//如过池塘没有鱼,前往下一个池塘
{
if(nu[j]==0)
stay++;
else
break;
}
}
//如果还有时间但是没有鱼了
if(hour>0)
sum[i][1]+=hour;
}
int staying=1;
for(int i=2; i<=n; i++)//寻找最大值
if(sum[i][0]>sum[staying][0])
staying=i;
for(int i=1; i<=n; i++)//输出每个湖所呆的时间
{
printf("%d",sum[staying][i]*5);
if(i!=n)
printf(", ");
}
printf("\nNumber of fish expected: %d\n",sum[staying][0]);
}
int main()
{
while(scanf("%d",&n),n)
{
if(flag!=0)
printf("\n");
flag=1;
memset(sum,0,sizeof(sum));
scanf("%d",&h);
for(int i=1;i<=n;i++)
scanf("%d",&fi[i]);
for(int i=1;i<=n;i++)
scanf("%d",&di[i]);
for(int i=1;i<n;i++)
scanf("%d",&ti[i]);
h=h*12;
slove();
}
}