洛谷P2678 [NOIP2015 提高组] 跳石头

P2678 [NOIP2015 提高组] 跳石头 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

这道题运用了贪心+二分(贪心做题时候更多凭借感觉,证明很难而且时间成本高,更多靠题感)

难点是我们应该拿什么进行二分

经过多次尝试和参考积累的经验,我们不难想到要将结果进行二分(这道题弄懂之后就会想到了)

若最大的最短跳跃距离为x, 那么我们就需要把石头之间距离小于x的石头移走

统计移走石头的个数进行判断,进而就知道应该往左还是往右二分,套用二分模板即可

这里还有一个核心巧妙的点是before变量的使用,可以从代码中体会

#include <iostream>
#include <algorithm>
using namespace std;
int a[50010];
int s, n, m;

int main()
{
	cin >> s >> n >> m;
	for (int i = 0; i < n; i++) cin >> a[i];
	
	//把可能的答案进行二分 
 	int l = 1, r = s, mid, i;
 	while (l < r)
 	{
 		mid = l + r + 1 >> 1; //下面有l=mid 避免死循环这里要+1 
 		int cnt = 0, before = 0; //cnt记录移走了多少石头, before记录上一个石头到起点的距离
		  
 		for (i = 0; i < n; i++) //枚举每个石头 
 		{
 			if (mid + a[i] > s) break; //如果再跳mid距离就超过总距离 那么直接break (主要判断最后一个石子到终点的距离) 
 			
 			if (a[i] - before < mid) cnt++; //两石头的距离小于mid 则移走 
 			else before = a[i]; //否则记录before 
		}
		
		cnt += n - i;//如果break了 就把i后面的是石头全部移走 
		
		if (cnt <= m) l = mid;
		else r = mid - 1; //二分模板 
	}
	
	cout << l;
	return 0;
}

类似做法的题目 洛谷P3853 [TJOI2007]路标设置 、 洛谷P1182 数列分段 Section II

### NOIP 2015 提高 石头 Python 解题思路 #### 动态规划求解最小踩石子数目 对于给定的独木桥长度以及青蛙跃距离范围,目标是最小化青蛙过河过程中踩到的石子数量。此问题可以通过动态规划来解决。 定义 `dp[i]` 表示到达第 `i` 块石子位置时所踩过的最少石子数[^3]。初始化数 `dp` 的大小为石子总数加一,并设定初始值均为无穷大(表示不可达),除了起点外设为零因为起始处无任何代价。 遍历每一个可能作为新一步起点的位置 `i` 和每一块可至的新位置 `j` ,更新 `dp[j]` 。具体来说,在每次尝试从某一点跃向另一点的过程中,如果该次跃有效,则比较当前记录下的最优方案与此次新增路径哪个更优并据此调整: ```python import sys def min_stones(n, m, stones): INF = float('inf') # 初始化dp表 dp = [INF] * n dp[0] = 0 for i in range(m): # 对于每一颗石子 for j in range(i + 1, n): # 尝试跃到后面所有的石子上去 distance = abs(stones[j] - stones[i]) if L >= distance >= D and dp[i] != INF: dp[j] = min(dp[j], dp[i] + 1) return min([val for idx,val in enumerate(dp) if stones[idx]>=L]) if any(stones>=L for stones in stones[m:]) else "无法完成" n, l, d, m = map(int, input().split()) stones_position = list(map(int, input().strip().split())) print(min_stones(n, l, d, m)) ``` 上述代码实现了基于动态规划算法计算最短路径的思想,其中 `min_stones()` 函数接收四个参数分别为:总共有多少块石子、独木桥全长、允许的最大单步跨度、已知存在几块固定不动的大石子;而输入部分则提供了这些数据的具体数值形式供调用者传入实际测试案例使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值