钓鱼

   
 
【训练题】钓鱼
 
 
时间限制:1秒  内存限制:64M
 
   

 

 

 

 

【问题描述】

 

 


  约翰是个垂钓谜,星期天他决定外出钓鱼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


 

 

 

首先,要认真审题!

对于不管是钓鱼还是行走,都是以5分钟为一个时间单位,所以总时间可以写为H*12;

看到这道题的数据范围与题目,我们不难想到状态转移方程f(i,j)表示前i个鱼塘我花j个时间单位最多可以钓到多少条鱼;

对于这道题来说,现在那个鱼塘钓鱼其实是没有关系的,为什么呢?假如你在第二个鱼塘钓了2个时间单位,在第一个鱼塘钓3个时间单位,最后的时间都可以写成第一个鱼塘钓的时间+走到第二个所需的时间+第二个鱼塘钓鱼的时间,而钓的鱼的数量是第一个鱼塘的加上第二个鱼塘的;

所以当我们在第i个鱼塘,如果可以从第j个时间单位开始钓鱼,那么我们可以从第j个时间单位一直在第i个鱼塘钓到H*12个时间单位;

然而第i个鱼塘的初始状态该怎么设定呢?若第i-1个鱼塘的第j个时间单位可以钓到X条鱼,那么在第i个鱼塘的第j+t[i-1]也可以钓到X条鱼

所以状态转移方程可以写为 先初始第i个鱼塘的值 f(i,j)=f(i-1,j-t[i-1]) (j>=t[i-1])

             然后对第i个鱼塘进行状态转移 if(f(i,j)) f(i,j+k)=MAX(f(i,j+k),f(i,j)+p(p代表在第i个鱼塘钓k分钟可以钓多少条鱼)) (j+k<=H*12)  //这里的j需要从大往小扫,请想想为什么!

 

边界f(1,0)=0;

最后答案MAX(f(i,j)) (i<=N j<=H*12)

 

程序:

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

using namespace std;

int N,H;
int f[30],d[30],t[30];
int p[30][1000];
int g[30];

void Ready()
{
 g[1]=0;
 scanf("%d%d",&N,&H);
 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]);
  g[i+1]=g[i]+t[i];
}
  memset(p,-1,sizeof(p));
  p[0][0]=0;
  t[0]=0;
}

int MAX(int x,int y)
{
 return x>y?x:y;
}

void Working()
{
 int x,y,q;
 int tot=H*60/5;
 for(int i=1;i<=N;i++)
 {
 
  for(int j=0;j<=tot;j++)
   {
     if(j>=t[i-1])
   if(p[i-1][j-t[i-1]]!=-1)
    {
     p[i][j]=p[i-1][j-t[i-1]];
    } 
   }
   for(int r=tot;r>=0;r--)
    {
    q=f[i];
     if(p[i][r]!=-1)
   for(int j=1;j<=tot;j++)
    {
       
        p[i][r+j]=MAX(p[i][r+j],p[i][r+j-1]+q);
        if(q>d[i])q-=d[i];
        else q=0;
   }
   
    }
      } 
      
      int ans=-1;
      for(int j=1;j<=N;j++)
      for(int i=0;i<=tot;i++)
       if(ans<p[j][i])ans=p[j][i];
printf("%d",ans);
}

int main()
{
 Ready();
 Working();
 return 0;
}


 

肯定还有更简单更简洁的方法。。。但我的智商有限。。。

 

重庆一中 吴松隐

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值