• POJ1042 Gone Fishing


    题目来源:http://poj.org/problem?id=1042

    题目大意:

      John有h个小时的时间想去钓鱼。(1<=h<=16).有n个池塘(2<=n<=25),它们的分布沿着一条单行的小路。John从第一个池塘处出发,他可以沿着小路向前走,在想停下来的池塘处钓鱼,对于路径的终点没有限制。为了钓到最多的鱼,John对各个池塘做了调查。若给路径上的池塘依次编号,,则对于每个池塘,开始钓鱼时,每5分钟内期望是可以钓到f[i]条鱼,随着时间的推移,每过5分钟,可以钓到的鱼减少d[i]条。若某个5分钟的时间段内可以钓到的鱼少于等于d[i],则下一个5分钟在这个池塘就钓不到鱼了。用t[i]表示从池塘 i 到池塘 i+1 所需要的时间。单位是5分钟(==!),  即:若t[3] = 4,表示从池塘3到池塘4需要4*5=20分钟。John在每个池塘钓鱼的时间都必须是5的倍数。求期望能钓到最多鱼的钓鱼计划,并输出在每个池塘钓鱼的时间(分钟为单位)和能钓到的鱼总数。当有多个方案都是最优解时,选择在第一个湖的时间最长的方案,若仍相等,选择在第二个湖时间最长的方案,依此类推。

    输入:每个测试用例,首先给出池塘数n,然后是时间h(小时为单位),接下来的两行分别有n个整数,分别表示f[i]和d[i],接下来的一行为n-1个整数,表示t[i].n为0时表示输入结束。

    输出:对于每个测试用例,第一行依次输出在每个池塘的停留时间(分钟为单位),每个时间之间用逗号+空格分开。第二行输出能钓到的最多的鱼的数量,格式见Sample.


    Sample Input

    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 

    Sample Output

    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

    本题可以用 DP or 枚举+贪心 的方法做。


    DP的状态和状态转移:

    dp[i][j]表示第j个五分钟时John位于池塘 i 的情况最多可以钓到多少鱼。

    dp[i][j] = max(dp[i][j], dp[i - 1][j - t[i] - k]);

    实际处理时,对于所有可行的k: dp[i + 1][j + k + t[i]] = max(dp[i + 1][j + k + t[i]], dp[i][j] + sum), 其中sum是在i+1处钓鱼k个5分钟所钓到的鱼。


     实际上枚举+贪心的方法更容易,数据量不大,所以速度更快。

    我们可以把总时间分为两个部分:在路上的时间和在钓鱼的时间。由于路是单行的,所以在路上的时间取决于走的最远距离,即到达的池塘的最大编号。 剩余的时间用于钓鱼。我们可以把移动+钓鱼的混合过程拆分为移动的过程和钓鱼的过程,即指定一个池塘为终点,移动过程即从起点到终点的过程,钓鱼的过程就是从起点到终点的各个池塘中选择池塘钓鱼,因为移动过程所需的时间已经在前面考虑过了,这个时候我们就可以认为需要移动的时候可以直接瞬间到达。然后,选择到哪些池塘钓鱼的策略采用贪心的方法,每个钓鱼的5分钟都选择期望最大的那一个池塘,每在选择一个池塘钓鱼5分钟,减少相应池塘的期望,增加计划中在该池塘钓鱼的时间,然后继续选择期望最大的池塘,直到钓鱼的时间不够,或者池塘里没有鱼了。如果池塘没有鱼了,还有时间的话,把多余的时间分配给第一个池塘。

    以上解释的是贪心策略,枚举所有池塘作为终点时贪心结果,再选择最优的方案即可。

    由于数据规模不大,每一步贪心的时候都直接遍历数组实现了,有人提到了用堆来做,也许能快一些。

     1 //////////////////////////////////////////////////////////////////////////
     2 //        POJ1042 Gone Fishing
     3 //        Memory: 228K        Time: 110MS
     4 //        Language: C++        Result: Accepted
     5 //////////////////////////////////////////////////////////////////////////
     6 
     7 #include <iostream>
     8 
     9 using namespace std;
    10 
    11 int m;        //分钟数
    12 int n;        //池塘数
    13 int f[25];    //池塘初始鱼数
    14 int d[25];    //鱼每5分钟减少数目
    15 int left_fish[25];    //剩下的鱼
    16 int t[24];    //每两池塘之间的路径长度
    17 int plan[25];    //每个池塘的停留时间
    18 int temp[25];
    19 int max_cnt;    //最大期望
    20 int cnt;
    21 
    22 inline void update() {
    23     for (int i = 0; i < n; ++i) plan[i] = temp[i];
    24 }
    25 
    26 void process() {
    27     memset(plan, 0, sizeof(plan));
    28     max_cnt = -1;
    29     int flag = true;
    30     int time_on_the_road = 0;
    31     int time_fishing = m;
    32     //枚举所有池塘为终点的情况
    33     for (int i = 0; i < n; ++i) {
    34         cnt = 0;
    35         memset(temp, 0, sizeof(temp));
    36         time_fishing = m - time_on_the_road;
    37         for (int k = 0; k < n; ++k) left_fish[k] = f[k];
    38         
    39         //greedy
    40         while (true) {
    41             if (time_fishing < 5) break;    //时间耗完了 
    42             int most = -1;
    43             int lake_id;
    44             for (int j = 0; j <= i; ++j) {
    45                 if (left_fish[j] > most) {
    46                     most = left_fish[j];
    47                     lake_id = j;
    48                 }
    49             }
    50             if (most == 0) {
    51                 temp[0] += time_fishing / 5 * 5;
    52                 break;    //没有鱼了
    53             }
    54             temp[lake_id] += 5;
    55             cnt += left_fish[lake_id];
    56             left_fish[lake_id] -= d[lake_id];
    57             if (left_fish[lake_id] < 0) left_fish[lake_id] = 0;
    58             time_fishing -= 5;
    59         }
    60         if (cnt > max_cnt) {
    61             max_cnt = cnt;
    62             update();
    63         } else if (cnt == max_cnt) {
    64             for (int i = 0; i < n; ++i) {
    65                 if (temp[i] < plan[i]) break;
    66                 if (temp[i] > plan[i])    update();
    67             }
    68         }
    69         time_on_the_road += t[i];
    70         if (time_on_the_road > m) break;    //不可能走到该池塘
    71     }
    72     cout << plan[0];
    73     for (int i = 1; i < n; ++i) cout << ", " << plan[i];
    74     cout << endl << "Number of fish expected: " << max_cnt << endl << endl;
    75 }
    76 
    77 int main(void) {
    78     while (true) {
    79         cin >> n;
    80         if (n == 0) break;
    81         cin >> m;
    82         m *= 60;    //小时转化为分钟
    83         for (int i = 0; i < n; ++i) cin >> f[i];
    84         for (int i = 0; i < n; ++i) cin >> d[i];
    85         for (int i = 0; i < n - 1; ++i) {
    86             cin >> t[i];
    87             t[i] *= 5;    //转为分钟数
    88         }
    89         process();
    90     }
    91     return 0;
    92 }
    View Code  
  • 相关阅读:
    Processing中PImage类和loadImage()、createImage()函数的相关解析
    基于Maxmspjitter的基础【pixel shader】绘制模板Patcher
    Processing多窗口程序范例(三)
    SpringBoot:基于注解的@CachePut
    Android开发—错误记录1:W/System.err: java.net.ConnectException: Connection refused
    自控力第一章-我要做,我不要,我想要:什么是意志力?为什么意志力至关重要
    超算结课小结
    linpack_2
    搭建Linpack
    汇编程序返回dos
  • 原文地址:https://www.cnblogs.com/dengeven/p/3244424.html
Copyright © 2020-2023  润新知