【貪心】【二分】[NOIP2015]跳石頭

peterzh6發表於2024-10-03

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];
    }
    
    sort(rocks.begin(), rocks.end()); // 排序
    
    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;
}

相關文章