题目大意不再赘述。
概述:最优计划时,John最后结束时,一定在某个湖(这是肯定的吧,这是枚举思想),并且由于计划最优,路程上花的时间一定最少。
所以本题的思路是:先枚举n种情况,John最后停在了某个湖i(i=1,2,...,n)并且,每种方法都是经过某种精密计算,在每个湖以及路程的分配上是最优的;最后全局最优的方案就是前面的n种方案里最好的。
方法1:假设John最后停在第i个湖为最优方案,由于计划最优,John通过某种方法可以准确得知他在某个湖上花的时间,时间一到他马上赶去下一个湖,没有来回,全程只有单向不回头的路途,并准确掌握时间每个湖花的时间,最后停在第i个湖上。
【等会会说明为什么用“最后停”这样的字眼】
方法2:由于在某个湖上花的时间我们可能比较难以得知,因此呢,我们就有一种贪心的方法:假设John最优的计划最后停在了第i个湖上,先一次性减去第1个湖到第i个湖的路程花销总时间Σtk(k=1,2,...,i);然后每5分钟查看这些湖中那个湖的鱼最多,就去那个湖钓5分钟(不计较路程开销“瞬移”,钓完此湖减少相应的d值),再看哪个湖里鱼最多,以此类推,直到时间用尽。
方法2等价于方法1.为何等价?思考一下就可以得知了,就是原本连续的一段粒度大的钓鱼时间被分割为多次细粒度的钓鱼时间,但总体各自分布的时间是一致的。
至于为何用“最后停”,因为,开始时一次性减去的时间决定了John必须最后走到第i个湖(实际上有可能John不需要走到后面),也可能枚举出“John只停留在某个湖k钓鱼是最优,而却需要抽出时间多走到后面的湖i”的情形,那更优的情形就出现在前面枚举的情形k上了。
PS:据说本题为贪心经典问题(贪心+枚举,确实思路很有启发意义啊“不过我为何没有看答案却想不出来呢?”)
附上代码
#include <stdio.h> #include <memory.h> #include <limits.h> #define N 25 int main(){ int n,h,i,j; int fi[N],di[N],ti[N]; int time[N][N]; int Inlake[N]; //Inlake[i] means the man end up the trip at lake i;and he can fish in lake 0 to lake i while(1){ scanf("%d",&n); if(n == 0) break; scanf("%d",&h); h = h * 12;//h 个 5-minutes for(i = 0; i < n; i++) scanf("%d",&fi[i]); for(i = 0; i < n; i++) scanf("%d",&di[i]); for(i = 0; i < n - 1; i++) scanf("%d",&ti[i]); //input over for(i = 0; i < n; i++){ Inlake[i] = 0; memset(time[i],0,sizeof(time[i])); int tmp = h,tmp2 = 0; int fitmp[N]; for(j = 0; j < n; j++) fitmp[j] = fi[j]; for(j = 0; j < i; j++) tmp2 += ti[j]; tmp-=tmp2;//减去所有路程时间后,John可以在lake 0到lake i之间“瞬移” while(tmp>0){ int max = INT_MIN,index = -1; for(j = 0; j <= i; j++) if(fitmp[j] > max){ max = fitmp[j]; index = j; } time[i][index]++; Inlake[i] += fitmp[index]; fitmp[index] -= di[index]; if(fitmp[index] < 0) fitmp[index] = 0; tmp--; } } int max = INT_MIN,index = -1; for(i = 0; i < n; i++) if(Inlake[i] > max){ max = Inlake[i]; index = i; } //printf("output\n"); for(i = 0; i < n; i++){ if(i != n-1) printf("%d, ",time[index][i]*5); else printf("%d\n",time[index][i]*5); } printf("Number of fish expected: %d\n\n",Inlake[index]); } return 0; }