【贪心】【二分】[NOIP2015]跳石头
https://ac.nowcoder.com/acm/contest/22353/C
正确的思路是二分查找 + 贪心。具体来说,可以通过二分来猜测一个最小的跳跃距离,然后通过贪心算法判断是否可以通过移除石头使所有的跳跃都满足这个最小跳跃距离。这种方法的核心是逐步逼近最优解,而不是直接删除前 m 小的元素。
细节:在判断最小跳跃距离时没有考虑到终点 l,也就是在最后一个石头到终点的距离没有考虑,这会导致一些边界情况出错。
#include<bits/stdc++.h>
using namespace std;
int main() {
int l, n, m;
cin >> l >> n >> m;
vector<int> rocks(n + 2); // 包含起点和终点
rocks[0] = 0; // 起点
rocks[n + 1] = l; // 终点
for(int i = 1; i <= n; i++) {
cin >> rocks[i];
}
int left = 1, right = l, ans = 0;
while(left <= right) {
int mid = left + (right - left) / 2;
int removed = 0;
int prev = 0; // 记录上一个保留的石头位置
// 贪心地判断是否可以移除石头以保证最小跳跃距离至少为 mid
for(int i = 1; i <= n + 1; i++) {
if(rocks[i] - rocks[prev] < mid) {
removed++; // 移除当前石头
} else {
prev = i; // 保留当前石头
}
}
if(removed > m) {
// 移除的石头超过了限制,说明 mid 过大,缩小范围
right = mid - 1;
} else {
// 可以保证跳跃距离至少为 mid,尝试更大的跳跃距离
ans = mid;
left = mid + 1;
}
}
cout << ans << endl; // 输出结果
return 0;
}