zoukankan      html  css  js  c++  java
  • 贪心-钓鱼问题

    钓鱼问题:
    有n(2<=n<=25) 个湖从左到右一字排开。从第i个湖走到第i+1个湖要耗时t[i]
    个时间片(每个时间片 5 分钟)。John有 h(1<=h<=16) 个小时可以用在这些
    湖钓鱼(包括湖间行走时间)。在每个湖待的时间必须是整数个时间片或 0 。
    就算钓不着鱼了,也可以在湖边呆着。对于湖i John在那里的第一个时间片可以
    钓到鱼f[i]条,且后续的每个时间片,能钓到的鱼数量都比上一个时间片少d[i]。
    如果预计在一段时间内捕获的鱼的数量小于或等于di,则在下一个时间段内湖中
    将不再有鱼。为了简化规划,约翰假定没有其他人会在湖边钓鱼,以影响他期望
    捕获的鱼的数量。
    注意John只能 从第一个湖出发,从左往右走,不能回头 。最后John要停在哪里
    都可以。问John最多能钓多少条鱼。还要输出钓鱼方案,即在每个湖各呆多长时
    间。如果有多种方案,则优先选择在第一个湖呆时间最长的。如果还有多种,则
    优先选择在第二个湖呆的时间最长的……

    输入:
    您将在输入中获得一些案例。每种情况都以包含n的行开始。这后面跟着一个包含h的行。
    接下来,有一行n个整数指定fi(1<=i<= n),然后是一行n个整数di(1<=i<=n),
    最后是一行n-1个整数ti 1<=i<=n-1)。输入由n=0的情况终止。

    数据输出:
    对于每个测试案例,打印每个湖泊花费的分钟数(以逗号分隔),以实现预计捕获的
    鱼数量最大的计划(即使超过80个字符,您应该在一行上打印整个计划)。接下来是
    一条包含预期鱼类数量的线。如果存在多个计划,则选择在湖1尽可能长时间花费的计划,
    即使预计在某些间隔内不会捕获鱼。如果还有一条路径,选择在湖边2尽可能长的那一条,
    等等。在个案之间插入一个空行。

    输入:
    2 --几个湖
    1 --1个小时
    10 1 --第1个5分钟的时间片,第1个湖可以钓10条鱼,第2个湖可以钓1条鱼
    2 5 --每个时间片后,每个湖减少的鱼的数量
    2 --从1湖走的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

    难点:走路时间可多可少,不知道到底该花多长时间纯钓鱼才最好
    (可能有好湖在很右边)。
    解决:枚举最终停下来的湖,将方案分成n类。每类方案的走路时间就是确定的。
    在每类方案里找最优解,然后再优中选优。

    贪心:在确定停下来的湖是x的情况下,假定纯钓鱼时间是k个时间片。
    用三元组(F,i,j) (i<=x,1<=j<= k)表示湖i的第j个时间片能够钓的鱼的数目是F
    将所有的(F,i,j 共x*k个)按F值从大到小排序,选前k个,就构成了最佳钓鱼方案

    本题思路就是枚举最终停下来的湖,这样就能算出纯钓鱼的时间片个数 K 。
    然后用一个三元组(F,i,j)表示第i个湖的第j个时间片所能钓到鱼的数量为F。
    然后按照钓鱼的数量从大到小排序,取前K个即是问题的答案!

    思路:采用贪心策略:
    假设他从1湖泊走到x湖泊,这还剩下Y个时间,(单位时间为5分钟)。
    然后再用剩下的时间去钓1-x的湖泊的鱼。每次都选择最多鱼的湖泊钓。
    由于每个湖都必须经过,且只经过一次,所以john花在路中的总时间是确定的。
    在这个条件下,可以想成john学会了“瞬间移动”,即:他可以在任何时间,
    移动到任何他想去的湖,而移动的过程无需时间。于是,john只需在每个
    5分钟的开始“瞬间移动”到当前5分钟中能钓到最多的鱼的湖中,且只钓5分钟的鱼。
    这样可以保证john钓到尽可能多的鱼。只要枚举john的行程是从第一个湖到
    第k个湖(1<=k<=n),比较出最大的钓鱼数,就是题目所求的最佳方案。
    贪心算法:每次选择一个局部最优策略进行实施,而不去考虑对今后的影响。
    采用贪心策略,每次选择鱼最多的湖钓一次鱼,可以认为约翰能从一个湖
    “瞬间转移”到另一个湖,即在任意一个时刻都可以从湖1到湖pos中任选一个钓一次鱼。
    直接用贪心策略,哪个湖现在每单位时间能钓的鱼数目最多,则在哪个湖钓。
    我们假设只在前i个湖钓鱼,那么我们走路的时间是不是可以求出来了。
    那么求出这个时间以后,用总时间减去走路时间就得到了能用与钓鱼的时间,
    在减去走路时间后,我们就可以在前i个湖之间直接“瞬移”既然可以瞬移的话,
    我们每次选择现在单位时间能钓的最多的鱼的湖,在这个湖钓一个单位时间,
    鱼总数增加,这个湖单位时间能掉的鱼减少,然后我们再次选择单位时间
    可以钓最多的湖,。。。(循环)。。。。。
    https://blog.csdn.net/an94460061/article/details/89424135
    https://blog.csdn.net/TYF_wind/article/details/86361484

    python代码实现:
     1 def main():
     2     # n个湖
     3     fi, di = [], []
     4     n = int(input())
     5     h = int(input())
     6     # 转换为分钟/5,得到总共呆多久的时间片
     7     p = h*60/5
     8     fi = list(map(int, input().split()))
     9     # 从1开始计算,方便理解
    10     fi.insert(0, 0)
    11     di = list(map(int, input().split()))
    12     di.insert(0, 0)
    13     ti = list(map(int, input().split()))
    14 
    15     # 遍历假设每个湖是终点,在所有时间片都用完的情况下,可以钓到鱼的数量放入一个list
    16     # 索引从1开始,方便后续理解
    17     # 假设第一个湖是终点,得到一个最大值,然后再假设第2个湖是终点,也得到一个最大值
    18     # 依次遍历所有的湖做终点,最后找出在哪个湖最大值,既是最好的方案
    19     fist_list = []
    20     # 最大可以钓鱼数量
    21     max_fish_num = 0
    22     for i in range(1, n+1):
    23         # 第一个湖第1个时间片所能钓到鱼的数量
    24         fish_num = fi[i]
    25         # 实际可以钓鱼用的时间片 = 总共的时间片-行走的时间片
    26         reality = 0
    27         # 第一次原地不动,所以不需要减去移动时间
    28         if i == 1:
    29             reality = int(p)
    30         else:
    31             reality = int(p - sum(ti[0:i-1]))
    32 
    33         for j in range(1, reality+1):
    34             fist_list.append([fish_num, i])
    35             # 捕获的鱼的数量小于或等于di,则在下一个时间段内湖中将不再有鱼
    36             if fish_num <= di[i]:
    37                 fish_num = 0
    38             else:
    39                 fish_num = fish_num - di[i]
    40 
    41         # 计算每次的最大可以钓鱼数量
    42         fist_list = sorted(fist_list, key=lambda x: x[0], reverse=True)
    43         """
    44             0-表示某个时间片所能钓鱼的数量,1-表示哪个湖
    45             [[10, 1], [8, 1],[6, 1],[4, 1],[2, 1], 
    46              [0, 1],[0, 1],[0, 1],[0, 1],[0, 1], 
    47              [1, 2],[0, 2],[0, 2],[0, 2],[0, 2], 
    48              [0, 2],[0, 2],[0, 2],[0, 2],[0, 2]]
    49 
    50             [[10, 1], [8, 1], [6, 1], [4, 1], [2, 1], 
    51              [1, 2], [0, 1], [0, 1], [0, 1], [0, 1], 
    52              [0, 1], [0, 2], [0, 2], [0, 2], [0, 2], 
    53              [0, 2], [0, 2], [0, 2], [0, 2], [0, 2]
    54             ]    
    55         """
    56         total_fish_num = 0
    57         # 计算终点是i湖可以钓到鱼的最大值
    58         for k in range(reality):
    59             total_fish_num += fist_list[k][0]
    60         # 如果新计算出来的值大于之前的值,说明目前的方案是最优的,
    61         # 需要更新最大值,同时要更新每个湖停留时间的方案
    62         if total_fish_num > max_fish_num:
    63             max_fish_num = total_fish_num
    64             lake_list = [0] * (n + 1)
    65             for c in range(reality):
    66                 lake_list[fist_list[c][1]] += 1
    67             # lake_list索引1位置,代表1湖
    68 
    69     for j in range(1, n+1):
    70         stop_time = lake_list[j] * 5
    71         print("%d " % stop_time, end="")
    72     print("")
    73     print("The total number of fish is:%d" % max_fish_num)
    74 
    75     return 0
    76 
    77 
    78 if __name__ == '__main__':
    79     main()
     
  • 相关阅读:
    协程方法的开启、关闭以及传参
    五种访问修饰符
    多态之虚方法、抽象类、接口
    递归算法
    继承之构造方法
    鼠标相关操作(Cursor类及相关API)
    遇到的问题(七)
    遇见的问题(六)
    遇见的问题(五)
    函数VS对象
  • 原文地址:https://www.cnblogs.com/an-wl/p/13512147.html
Copyright © 2011-2022 走看看