# Greedy# Binary Search

e464 - Error

🔗 前往 ZeroJudge 原題

題目描述

題目要求給定一個距離 rn 個點的位置 a[i],求最少需要多少個工人才能覆蓋所有點。工人可以覆蓋距離在 r 以內的點。

解題思路

這題可以使用貪心演算法和二分搜尋來解決。首先,將點的位置排序。然後,使用二分搜尋來尋找最少需要的工人數量。對於每個工人數量 m,我們使用貪心策略來判斷是否可以使用 m 個工人覆蓋所有點。貪心策略是從第一個點開始,盡可能地用一個工人覆蓋最多的點。如果無法用 m 個工人覆蓋所有點,則增加工人數量,否則減少工人數量。

複雜度分析

  • 時間複雜度: O(n log n + n log n) = O(n log n),其中 O(n log n) 是排序的複雜度,O(n log n) 是二分搜尋的複雜度。
  • 空間複雜度: O(n),用於儲存點的位置。

程式碼

#include <bits/stdc++.h>
using namespace std;
long long n,r,a[200005];
bool ok(long long m){
	int la=1;
	while(a[la]-a[0]<=r)++la;
	--la;
	--m;
	for(int i=la+1;i<n;++i){
		if(a[i]-a[la]>r){
			if(--m<0)return 0;
			int ti=i;
			while(i<=n&&a[i]-a[ti]<=r)++i;
			--i;
			la=i;
		}
	}
	return 1;
}
long long bs(long long l,long long r){
    if(l>r)return l;
    long long m=(l+r)/2;
    return (ok(m)?bs(l,m-1):bs(m+1,r));
}
int main(){
	cin.tie(0); ios::sync_with_stdio(0);
	while(cin >> r >> n){
		if(n==-1&&r==-1)return 0;
		if(r<0)r=0;
		if(n<=0){
			cout << "0\n";
			continue;
		}
		else if(n==1){
			cout << "1\n";
			continue;
		}
		for(int i=0;i<n;++i)
			cin >> a[i];
		sort(a,a+n);
		cout << bs(1,n) << "\n";
	}
	return 0;
}

Discussion