首页 > 代码库 > 黑书贪心例题之钓鱼 poj1042:Gone Fishing

黑书贪心例题之钓鱼 poj1042:Gone Fishing

总时间限制: 2000ms 内存限制: 65536kB描述John is going on a fishing trip. He has h hours available (1 <= h <= 16), and there are n lakes in the area (2 <= n <= 25) all reachable along a single, one-way road. John starts at lake 1, but he can finish at any lake he wants. He can only travel from one lake to the next one, but he does not have to stop at any lake unless he wishes to. For each i = 1,...,n - 1, the number of 5-minute intervals it takes to travel from lake i to lake i + 1 is denoted ti (0 < ti <=192). For example, t3 = 4 means that it takes 20 minutes to travel from lake 3 to lake 4. To help plan his fishing trip, John has gathered some information about the lakes. For each lake i, the number of fish expected to be caught in the initial 5 minutes, denoted fi( fi >= 0 ), is known. Each 5 minutes of fishing decreases the number of fish expected to be caught in the next 5-minute interval by a constant rate of di (di >= 0). If the number of fish expected to be caught in an interval is less than or equal to di , there will be no more fish left in the lake in the next interval. To simplify the planning, John assumes that no one else will be fishing at the lakes to affect the number of fish he expects to catch. Write a program to help John plan his fishing trip to maximize the number of fish expected to be caught. The number of minutes spent at each lake must be a multiple of 5.输入You will be given a number of cases in the input. Each case starts with a line containing n. This is followed by a line containing h. Next, there is a line of n integers specifying fi (1 <= i <=n), then a line of n integers di (1 <=i <=n), and finally, a line of n - 1 integers ti (1 <=i <=n - 1). Input is terminated by a case in which n = 0.输出For each test case, print the number of minutes spent at each lake, separated by commas, for the plan achieving the maximum number of fish expected to be caught (you should print the entire plan on one line even if it exceeds 80 characters). This is followed by a line containing the number of fish expected. If multiple plans exist, choose the one that spends as long as possible at lake 1, even if no fish are expected to be caught in some intervals. If there is still a tie, choose the one that spends as long as possible at lake 2, and so on. Insert a blank line between cases.样例输入2 1 10 1 2 5 2 4 4 10 15 20 17 0 3 4 3 1 2 3 4 4 10 15 50 30 0 3 4 3 1 2 3 0 样例输出45, 5 Number of fish expected: 31 240, 0, 0, 0 Number of fish expected: 480 115, 10, 50, 35 Number of fish expected: 724 来源East Central North America 1999

本题详细思路可以从黑书上得出,使用贪心法可解,但是有一个问题有没搞懂,黑书上写到普通的算法O(kn^2)的复杂度,没有问题,但是用堆为何就降为了O(knlogn)?

假设使用堆的话,那么一共n次枚举,而每一次枚举中,有k次从堆中取出最小值,但是每次枚举还需要话费时间来建堆,如果只算取最小值的时间复杂度,那么确实是O(knlogn),但是每一次枚举的过程中如果算上建堆的nlogn的时间的话,那么得出的复杂度结果应该是O( n(klogn+nlogn) ) 因为k<n,可以得出复杂度应该为O(n^2 * logn)才对。

故我使用了最朴素的遍历的方法来取最小值AC了本题。

贴上代码

#include <iostream>#include <stdio.h>#include <memory.h>using namespace std;int n;int coun[26] = {0}, temp[26]={0}, sum = 0;int f[26],d[26],t[26];int h = 0;int main(){    while(cin>>n)    {        if(n == 0)            break;        memset(f,0,sizeof(f));        memset(d,0,sizeof(d));        memset(t,0,sizeof(t));        scanf("%d",&h);        h *= 12;        for(int i = 0; i < n; i ++)            scanf("%d",&f[i]);        for(int i = 0; i < n; i ++)            scanf("%d",&d[i]);        for(int i = 0; i < n-1; i ++)            scanf("%d",&t[i]);        memset(coun,0,sizeof(coun));                sum = -1;        for(int i = 0; i < n; i ++)        {            memset(temp,0,sizeof(temp));            int tim = 0;            for(int j = 0; j < i; j ++)            {                tim += t[j];            }            tim = h - tim;            //printf("%d\n",tim);            int tf[26];            memcpy(tf,f,sizeof(tf));            /*for(int i = 0; i <n; i++)                printf("%d\n",tf[i]);             */            int ts = 0;            for(int k = 0; k < tim; k ++)            {                int ti = 0; //compute the max lake                int tn = 0; // the index                for(int j = 0; j <= i; j ++)                {    if( tf[j] > ti)                {                    ti = tf[j];                    tn = j;                }                }                if(ti == 0)                {                    temp[0] += tim - k;                    break;                }                ts += ti;                tf[tn] -= d[tn];                if( tf[tn] < 0 )                    tf[tn] = 0;                temp[tn] ++;            }            if(ts > sum)            {                sum = ts;                memcpy(coun,temp,sizeof(coun));            }        }        printf("%d",coun[0]*5);        for(int i = 1; i < n; i ++)            printf(", %d",coun[i]*5);        printf("\n");        printf("Number of fish expected: %d \n\n",sum);    }        return 0;}

 

本题要注意到一点点边界问题,我最开始的代码里,在每一次的case里,将sum初始值赋为了0,这会导致一种情况,如果给的例子里所有湖的鱼的数量都为0的话,那么由于if(ts>sum)这个条件(这个条件也不能改为等号,根据题意,在同等产量上应该是前面的湖花的时间尽量长,如果改为等号,则会使在后面湖花费更长时间的策略覆盖掉先前的策略),不会有任何计算结果来赋值给coun[26],输出就会是在每个湖上花的时间是0,而事实却不应该是这样,输出结果应该是在第一个湖上花了所有的时间。故将初始sum=-1.