zoukankan      html  css  js  c++  java
  • 黑书贪心例题之钓鱼 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
    ",tim);
                int tf[26];
                memcpy(tf,f,sizeof(tf));
                /*for(int i = 0; i <n; i++)
                    printf("%d
    ",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("
    ");
            printf("Number of fish expected: %d 
    
    ",sum);
        }
        
        return 0;
    }

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

  • 相关阅读:
    Linux磁盘、目录、文件操作命令
    VMware虚拟机网络环境类型
    ASCII
    关于String StringBuffer StringBuilder
    多线程并发编程
    TCP面向连接网络编程
    记一次渗透某XX站
    记一次对微信引流网站的简单渗透测试
    幕布V1.1.9最新版漏洞集合
    java代码审计文章集合
  • 原文地址:https://www.cnblogs.com/xiaoshen555/p/3878543.html
Copyright © 2011-2022 走看看