【问题描述】
约翰是个垂钓谜,星期天他决定外出钓鱼h小时(1≤h≤16),约翰家附近共有n个池塘(2≤n≤25),这些池塘分布在一条直线上,约翰将这些池塘按离家的距离由近到远编上号,依次为L1,L2,…,Ln,约翰家门外就是第一个池塘,所以他到第一个池塘是不用花时间的。
约翰可以任选若干个池塘由近到远地垂钓,并且在每个池塘他都可以呆上任意长的时间,但呆的时间必须为5分钟的倍数(即5分钟为一个单位时间),已知从池塘Li到池塘Li+1要化去约翰ti个单位时间。每个池塘的上鱼率预先也是已知的,池塘Li在第一个单位时间内能钓到的鱼为Fi(0≤Fi≤100),并且每当他在某一个鱼塘呆上一个单位时间后,该鱼塘单位时间内能钓到的鱼将减少一个常数di(0≤di≤100)。
现在请你编一个程序计算约翰最多能钓到多少鱼。
【输入格式】
第一行为一个整数n,第二行为一个整数h,第三行为n个用空格隔开的整数,表示Fi(i=1,2,…,n),第四行为n个用空格隔开的整数,表示di(i=1,2,…,n),第五行为n-1个用空格隔开的整数,表示ti(i=1,2,…,n-1)
【输出格式】
一个整数,表示约翰最多能钓到鱼的数量。
【输入样例】
2
1
10 1
2 5
2
【输出样例】
31
【数据范围】
2≤n≤25 , 1≤h≤16 , 0≤ti≤100 , 0≤Fi≤100 , 0≤di≤100
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,h,f[30][400],d[30],t[30],dp[30][400];
//dp[i][j]:前i个湖前j个单位时间的最大值
int main()
{
//freopen("in.txt","r",stdin);
while(~scanf("%d",&n) && n)
{
memset(f,0,sizeof(f));
scanf("%d",&h);
h=h*12;
for(int i=1;i<=n;i++)
{
scanf("%d",&f[i][1]);
}
for(int i=1;i<=n;i++)
{
scanf("%d",&d[i]);
}
for(int i=2;i<=n;i++)
{
scanf("%d",&t[i]);
}
t[1]=0;
for(int i=1;i<=n;i++)
{
for(int k=2;k<=h;k++)
{
if(f[i][k-1]<=d[i]) break;
f[i][k]=f[i][k-1]-d[i];
}
}
memset(dp,-1,sizeof(dp));
dp[0][0]=0;
for(int i=0;i<n;i++)
{
for(int j=0;j<=h;j++)
{
int sum=0;
for(int k=0;k<=h && dp[i][j]!=-1;k++) //在第i个湖钓k个单位时间
{
if(j+t[i+1]+k>h) break;
dp[i+1][j+t[i+1]+k]=max(dp[i][j]+sum,dp[i+1][j+t[i+1]+k]);
if(f[i+1][k+1]>0) sum+=f[i+1][k+1];
}
}
}
int mark=1,MAX=0;
for(int i=1;i<=n;i++)
{
if(MAX<dp[i][h])
{
MAX=dp[i][h];
mark=i;
}
}
int MMAX=MAX;
for(int i=mark;i>=2;i--)
{
int sum=0,k;
for(k=0;k<=h;k++)
{
if(MAX==sum+dp[i-1][h-k-t[i]])
{
f[i][0]=k;
break;
}
sum=sum+f[i][k+1];
}
h=h-t[i]-k;
MAX-=sum;
}
f[1][0]=h;
for(int i=1;i<n;i++)
{
printf("%d, ",f[i][0]*5);
}
printf("%d\n",f[n][0]*5);
printf("Number of fish expected: %d\n\n",MMAX);
}
return 0;
}