原题: 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;
}