pku1042 Gone Fishing

黑书中的经典题:枚举+贪心
把每钓5分钟鱼称为钓一次鱼。首先枚举John需要走过的池塘的数目X,即从池塘1走到池塘X。减去路上花去的时间T=sum(Ti) i=1...X-1,这样我们可以认为John能从一个池塘"瞬间转移"到另一个池塘,即在任意一个时刻都可以在池塘1到池塘X中任选一个钓一次鱼(很重要)。现在采用贪心策略,每次选择鱼最多的池塘钓一次鱼。对于每个池塘来说,由于在任何时候鱼的数目只和John在该池塘里钓鱼的次数有关,和钓鱼的总次数无关,所以这个策略是最优的。假设一共允许钓k次鱼,那么每次在N个池塘中选择鱼最多的一个钓。总的时间复杂度为O(kn^2)。(黑书中的解释)

 在最后的结果中,第一个最大值所对应的在每个池塘的钓鱼时间为题目要求的情况,因为如果John在后面的池塘钓了鱼,那么前面相应的时间就会减少。最后注意池塘中没有鱼的情况。

具体见代码

#include<stdio.h> 
#include<string.h> 
#include<stdlib.h> 
#define MAXN 26 
int main() 
{    
int n, h, tmp, sum, max;    
int i, j, k, p;    
int F[MAXN], f[MAXN], d[MAXN], t[MAXN] = {0}, ans[MAXN], ANS[MAXN];  
// f[MAXN]保存每次湖泊剩下的鱼,ans[MAXN]保存每次枚举中各个湖泊呆的时间,ANS[MAXN]表示每次枚举后的在湖泊呆的最佳时间
while (scanf("%d", &n) != EOF && n)   
{       
scanf("%d", &h);      
h *= 12;        
for (i = 0; i < n; i++)           
scanf("%d", &F[i]);       
for (i = 0; i < n; i++)            
scanf("%d", &d[i]);        
for (i = 1; i < n; i++)        
{            
scanf("%d", &tmp);            
t[i] = tmp + t[i-1];    //到达第i个湖所用的时间    
}       
memset(ANS, 0, sizeof(ANS));      
for (max = 0, i = 1; i <= n; i++)   // 枚举需要走过的湖泊的数目
{            
memset(ans, 0, sizeof(ans));             
for (j = 0; j < i; j++)                
f[j] = F[j];   //每次循环时,要恢复湖泊中原有的鱼的数目          
for (j = 0, sum = 0; j < h - t[i-1]; j++)   //h-t[i-1]表示可以钓的次数         
{                
for (p = 0, k = 1; k < i; k++) //每次选一个鱼最多的湖泊钓一次鱼                  
if (f[k] > f[p])                        
p = k;                
if (f[p] <= 0)         //该湖泊剩下的鱼少于零时,将剩下的所有时间都加到呆在第一个湖泊的时间上        
{                    
ans[0] += h - t[i-1] - j;                    
break;                
}                
sum += f[p];               
f[p] -= d[p];               
ans[p]++;     //累加在该湖呆的时间       
}            
if (sum > max)             
{                
max = sum;                
memcpy(ANS, ans, sizeof(ans));            
}            
if (sum == max)            
{                
for (j = 0; j < i; j++)                    
if (ans[j] != ANS[j])                      
break;                
if (ans[j] > ANS[j])   //钓的鱼的数目相同时,选最近的湖泊呆比较长的时间                
memcpy(ANS, ans, sizeof(ans));            
}       
}         
for (i = 0; i < n - 1; i++)             
printf("%d, ", ANS[i]*5);         
printf("%d\nNumber of fish expected: %d\n\n", ANS[n-1]*5, max);     
}     
return 0; 
}
posted @ 2011-07-26 18:12  枕边梦  阅读(241)  评论(0编辑  收藏  举报