贪心-钓鱼问题

钓鱼问题:
有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()

 

 
posted @ 2020-08-16 12:46  StudyNLP  阅读(547)  评论(0编辑  收藏  举报