钓鱼问题

转载自:http://blog.csdn.net/u013480600/article/details/38062437

题意:

       John现有h个小时的空闲时间,他打算去钓鱼。钓鱼的地方共有n个湖,所有的湖沿着一条单向路顺序排列(John每在一个湖钓完鱼后,他只能走到下一个湖继续钓),John必须从1号湖开始钓起,但是他可以在任何一个湖结束他此次钓鱼的行程。

此题以5分钟作为单位时间,John在每个湖中每5分钟钓的鱼数随时间的增长而线性递减。每个湖中头5分钟可以钓到的鱼数用fi表示,每个湖中相邻5分钟钓鱼数的减少量用di表示,John从任意一个湖走到它下一个湖的时间用ti表示。

求一种方案,使得John在有限的h小时中可以钓到尽可能多的鱼。输出具体在第i个湖花了多少时间,如果存在多个最优解,输出优先第1个,第2个..湖中花时间最多的解.

分析:

       首先我们可以肯定John钓鱼的时候如果从i走到了j号鱼塘肯定就不会回去了,否则浪费时间回头.(想想是不是) 所以John钓鱼花在走路的时间肯定是从i到i+1湖的时间.

       由于总时间= 钓鱼时间+走路时间. 所以我们枚举John最后钓鱼的湖是第i个,然后我们算出他一共花了多少时间走路,那么剩下的就是钓鱼花的时间.

       假设剩下x单位的钓鱼时间,且我们钓鱼在[1,i]号湖范围内钓,所以每单位时间选取当前可钓鱼数目最多的湖钓鱼. 最终我们能得到钓鱼最大数目.(虽然钓鱼顺序不是这样的,但是我们能通过合理的安排钓鱼顺序来达到这个解.即该解可行)

       最终我们只需要对比我们枚举不同的终结湖位置所得到的解,就可以得到最优解.

注意:

       对于初始能钓鱼的数目就全为0的情况(fi[i]数组全0),输出要注意.

       如果fi-d<0之后fi应该变成0.

       优先选择序号小的湖钓鱼.

最终我本来第一次交的代码就是对的,结果本题有个BUG,导致我无限超时,真是悲剧.最后通过不断的修改代码,找到了这个BUG,这应该是POJ的问题.代码41行指出了那个BUG.这不是我第一次发现POJ诡异BUG了…

AC代码:

[cpp]  view plain  copy
  1. #include<cstdio>  
  2. #include<cstring>  
  3. using namespace std;  
  4. const int maxn=30;  
  5.   
  6. int n,h;        //n表湖数目,h表单位时间 数目  
  7. int t[maxn];    //t[i]表从i湖走到i+1湖花的单位时间  
  8. int f[maxn];    //初始每单位时间能钓的鱼量  
  9. int d[maxn];    //每单位时间钓鱼量的减少量  
  10. int cf[maxn];   //当前每单位时间能钓的鱼量  
  11.   
  12. int ans;        //总钓鱼量  
  13. int sum[maxn];  //每个湖对应的钓鱼时间  
  14.   
  15. void get_max(int k,int &ans,int *sum)//选[1,k]内的湖,获得当前单位时间的钓鱼量,并更新对应数组  
  16. {  
  17.     int max_v=-1,id=-1;  
  18.     for(int i=1;i<=k;i++)//从前往后选,保证解不唯一时也符合要求  
  19.     if(cf[i]> max_v)  
  20.     {  
  21.         max_v=cf[i];  
  22.         id=i;  
  23.     }  
  24.     ans += cf[id];  
  25.     sum[id]++;  
  26.     cf[id] -=d[id];  
  27.     if(cf[id]<0) cf[id] = 0;  
  28. }  
  29. void solve()  
  30. {  
  31.     for(int i=1;i<=n;i++)   //枚举最后一个钓鱼的湖  
  32.     {  
  33.         int fish_time = h;  //仅用于钓鱼的时间  
  34.         for(int j=1;j<i;j++)  
  35.             fish_time = fish_time - t[j];  
  36.   
  37.         int temp_ans=0;//当前解  
  38.         int temp_sum[maxn]={0};//当前解  
  39.         memcpy(cf,f,sizeof(f));  
  40.   
  41.         for(int j=0;j<fish_time;j++)//神BUG,若此句改为 while(fish_time--) 则无限超时.原因不明  
  42.         {  
  43.             get_max(i,temp_ans,temp_sum);  
  44.         }  
  45.   
  46.         if(temp_ans > ans)//当前解更优  
  47.         {  
  48.             ans=temp_ans;  
  49.             memcpy(sum,temp_sum,sizeof(sum));  
  50.         }  
  51.     }  
  52.     for(int i=1;i<=n;i++)  
  53.     {  
  54.         if(i>1) printf(", ");  
  55.         printf("%d",sum[i]*5);  
  56.     }  
  57.     printf("\nNumber of fish expected: %d\n\n",ans);  
  58. }  
  59.   
  60. int main()  
  61. {  
  62.     while(scanf("%d",&n)==1&&n)  
  63.     {  
  64.         scanf("%d",&h);  
  65.         h= h*12;  
  66.         ans = 0;  
  67.         memset(sum,0,sizeof(sum));  
  68.         sum[1]= h;//默认当所有f=0时的解  
  69.         for(int i=1;i<=n;i++)  
  70.             scanf("%d",&f[i]);  
  71.         for(int i=1;i<=n;i++)  
  72.             scanf("%d",&d[i]);  
  73.         for(int i=1;i<=n-1;i++)  
  74.             scanf("%d",&t[i]);  
  75.         solve();  
  76.     }  
  77.     return 0;  
  78. }  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值