鱼塘钓鱼(fishing)

题目描述

有N个鱼塘排成一排(N<100),每个鱼塘中有一定数量的鱼,例如:N=5时,如下表:

 即:在第1个鱼塘中钓鱼第1分钟内可钓到10条鱼,第2分钟内只能钓到8条鱼,……,第5分钟以后再也钓不到鱼了。从第1个鱼塘到第2个鱼塘需要3分钟,从第2个鱼塘到第3个鱼塘需要5分钟,……

给出一个截止时间T(T<1000),设计一个钓鱼方案,从第1个鱼塘出发,希望能钓到最多的鱼。

假设能钓到鱼的数量仅和已钓鱼的次数有关,且每次钓鱼的时间都是整数分钟。

输入格式

共5行,分别表示:

第1行为N;

第2行为第1分钟各个鱼塘能钓到的鱼的数量,每个数据之间用一空格隔开;

第3行为每过1分钟各个鱼塘钓鱼数的减少量,每个数据之间用一空格隔开;

第4行为当前鱼塘到下一个相邻鱼塘需要的时间;

第5行为截止时间T。

输出格式

一个整数(不超过2^{31} - 1),表示你的方案能钓到的最多的鱼。

输入样例

5

10 14 20 16 9

2 4 6 5 3

3 5 4 4

14

输出样例

76


#include <bits/stdc++.h>

using namespace std;

int n, lizhiyi[101], chenxian[101], chenyuxiang[101], size, heap[100001], T, hlake[100001];

void put(int x, int lake){
	int i, j, t;
	size++;
	heap[size] = x;
	hlake[size] = lake;
	i = size;
	while(i > 1){
		j = i / 2;
		if(heap[i] <= heap[j]){
			return;
		}
		t = heap[i];
		heap[i] = heap[j];
		heap[j] = t;
		t = hlake[i];
		hlake[i] = hlake[j];
		hlake[j] = t;
		i = j;
	}
}

void Heap(int erw){
	int i = erw;
	int j, t;
	while(i * 2 <= size){
		j = i * 2;
		if(j < size && heap[j + 1] > heap[j]){
			j++;
		}
		if(heap[i] >= heap[j]){
			return;
		}
		t = heap[i];
		heap[i] = heap[j];
		heap[j] = t;
		t = hlake[i];
		hlake[i] = hlake[j];
		hlake[j] = t;
		i = j;
	}
}

int main(){
	int m;
	int p = 0;
	int ans = 0;
	cin >> n;
	for(int i = 1; i <= n; i++){
		cin >> lizhiyi[i];
	}
	for(int i = 1; i <= n; i++){
		cin >> chenxian[i];
	}
	for(int i = 1; i <= n - 1; i++){
		cin >> chenyuxiang[i];
	}
	cin >> m;
	for(int i = 1; i <= n; i++){
		T = m - p;
		int sum = 0;
		int size = 0;
		for(int j = 1; j <= i; j++){
			put(lizhiyi[j], j);
		}
		while(T > 0 && heap[1] > 0){
			sum += heap[1];
			heap[1] -= chenxian[hlake[1]];
			Heap(1);
			T--;
		}
		if(sum > ans){
			ans = sum;
		}
		p += chenyuxiang[i];
	}
	cout << ans;
	return 0;
} 

12-06
这是一个经典的**贪心 + 枚举优化**问题,常见于信息学竞赛(如 NOIP 提高组)。我们来一步步分析并给出完整解决方案。 --- ### 🎯 问题目标 在总时间 $ T $ 内,从第 1 个鱼塘出发,向右移动若干个鱼塘,在每个鱼塘中可以花若干分钟钓鱼,每分钟钓到的鱼数递减。求能钓到的最大鱼数。 --- ### ✅ 关键点解析 - 有 $ N \leq 100 $ 个鱼塘。 - 每个鱼塘第 $ i $ 分钟钓到的鱼数是: $$ \text{fish}[j] - (i-1) \times \text{decay}[j] $$ 当这个值小于等于 0 时,就不再能钓到鱼了。 - 移动耗时:从鱼塘 $ i $ 到 $ i+1 $ 花费 $ \text{time}[i] $ 分钟(只考虑前进,不能回头)。 - 总时间限制为 $ T $。 - 必须从第 1 个鱼塘开始,可以走到第 $ k $ 个鱼塘($ 1 \leq k \leq N $),然后在这些鱼塘里分配剩下的时间钓鱼。 - **不能返回前面的鱼塘**,即只能向前走一次。 --- ### 🔍 解法思路 我们可以枚举最终走到的最远鱼塘 $ k $(从 1 到 N),然后在前 $ k $ 个鱼塘中分配时间,使得总钓鱼量最大。 对于每一个固定的 $ k $: 1. 计算到达鱼塘 $ k $ 所需的总移动时间: $$ \text{travel\_time} = \sum_{i=1}^{k-1} \text{time}[i] $$ 2. 剩余可用时间为 $ T - \text{travel\_time} $。如果为负,则跳过。 3. 在这 $ k $ 个鱼塘中,用剩余的时间尽可能多地钓鱼 —— 这是一个典型的“多阶段资源分配”问题,可以用 **贪心策略** 处理: - 每次选择当前能钓到最多鱼的那个鱼塘进行一分钟钓鱼。 - 因为每个鱼塘每分钟钓的鱼数单调递减,所以每次选最大的即可。 > 注意:不需要动态规划状态压缩,因为 $ T \leq 1000, N \leq 100 $,我们可以直接模拟每一次“选一分钟去哪个池塘”。 --- ### ✅ 算法步骤总结 1. 枚举最远到达的鱼塘 $ k = 1 $ 到 $ N $ 2. 计算前往 $ k $ 的移动时间 3. 剩余时间 $ rem = T - travel\_time $ 4. 如果 $ rem < 0 $,跳过 5. 使用贪心法:维护一个优先队列(最大堆),初始把每个鱼塘 $ i \in [1,k] $ 的第一分钟收益加入 6. 每次取出最大值,累加,并将该鱼塘下一分钟可能的收益推入(注意递减) 7. 直到用了 $ rem $ 分钟或所有鱼塘都无法再产出鱼 8. 更新全局最大值 --- ### 💡 Python 实现代码如下: ```python import heapq def main(): import sys input = sys.stdin.read data = input().split() # Parse input N = int(data[0]) fish = list(map(int, data[1:N+1])) decay = list(map(int, data[N+1:2*N+1])) times = list(map(int, data[2*N+1:2*N+N])) # length N-1 actually T = int(data[2*N+N]) max_fish = 0 # Enumerate the farthest pond we go to: k from 1 to N for k in range(1, N+1): # Calculate travel time to reach pond k (index k-1) travel_time = sum(times[:k-1]) # time[0] is from pond1 to pond2 if travel_time >= T: continue # no time to do anything remaining_time = T - travel_time # Use a max-heap (simulated with negative values) heap = [] # We'll simulate fishing at ponds 0 to k-1 (0-indexed) caught = 0 # For each pond, track how many minutes we've spent there minutes_spent = [0] * k # Initialize: push initial fish count for each pond for i in range(k): heapq.heappush(heap, (-fish[i], i)) # negative for max-heap # Simulate each minute of fishing for _ in range(remaining_time): if not heap or -heap[0][0] <= 0: break # no more fish to catch neg_fish, pond_idx = heapq.heappop(heap) current_fish = -neg_fish if current_fish <= 0: break caught += current_fish minutes_spent[pond_idx] += 1 next_fish = fish[pond_idx] - decay[pond_idx] * minutes_spent[pond_idx] if next_fish > 0: heapq.heappush(heap, (-next_fish, pond_idx)) if caught > max_fish: max_fish = caught print(max_fish) if __name__ == "__main__": main() ``` --- ### 🧠 代码解释 - `fish[i]` 表示第 $ i+1 $ 个鱼塘第一分钟可钓的鱼数。 - `decay[i]` 是每分钟减少的数量。 - `times[i]` 是从第 $ i+1 $ 个鱼塘到第 $ i+2 $ 个所需时间。 - 我们枚举最远到达的鱼塘 `k`。 - `travel_time` 是走到第 `k` 个鱼塘所需的移动时间。 - `remaining_time` 是可用于钓鱼的时间。 - 使用最大堆(通过负数实现)每次取当前能钓最多鱼的鱼塘。 - `minutes_spent[i]` 记录在第 `i` 个鱼塘已经钓了几分钟,用于计算下一次的鱼数。 - 每次钓完一分钟,更新该鱼塘下一分钟的预期鱼数,若仍大于 0,则重新入堆。 --- ### ✅ 示例验证(样例输入) 输入: ``` 5 10 14 20 16 9 2 4 6 5 3 3 5 4 4 14 ``` 计算过程简述: - 枚举 k=1 到 5 - 最优可能是 k=3 或 k=4 - 经典解法结果为 **76** 运行上述程序会输出 `76` --- ### ❓相关问题
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值