1. 程式人生 > 實用技巧 >【題解】洛谷P6174 [USACO16JAN] Angry Cows S

【題解】洛谷P6174 [USACO16JAN] Angry Cows S

題目大意

給出直線上的若干點和炸彈數量,求一個炸彈能夠影響到的最小半徑,使得在規定的數量內炸彈可以覆蓋所有點。

分析

一讀題就是二分答案啊(


二分答案

適用範圍:求能使的題目所述條件得到滿足的答案的最值

前提條件:答案在區間內有單調性

實現方式:先確定答案所在的資料範圍,每次取區間的中點數值,並詢問這個值能否用做答案,以此為基礎逐步縮小答案的範圍,最後使得區間的左右邊界重合或左右交換,此時的邊界數值就是所求的答案啦~

二分答案在適用的條件下只用幾十次詢問就可以得到答案,經常與DP等演算法放在一起考察,能夠對題目進行很好的簡化,是一種常用的演算法思想。


本題就是一道典型的二分答案題,我們每次二分炸彈的爆炸半徑

,其最小為一,最大就是當前所有點座標的最值之差除以二(然鵝本人程式碼裡用的是最大點座標QAQ)

判斷是否符合條件時直接模擬就可以啦~

我在這裡用了貪心的思想,把炸彈認為是一個區間的話,這個炸彈的最大效用一定是在它以當前最近的點的作為區間起點的時候,以此來進行對答案可行性的判斷。

分析結束就上程式碼罷

Code

#include<bits/stdc++.h>
#define ull uneigned long long
#define ll long long
#define db double
using namespace std;
const int M=50005;
int n,m;
int a[M];
bool check(int x)
{
	int len=a[1]+x*2,cnt=1;
	for(int i=1;i<=n;i++){
		if(a[i]<=len) continue;
		else{
			len=a[i]+2*x;
			cnt++;
		}
		if(cnt>m) return 0;//當此時用到的炸彈數量大於題目條件時return 
	}
	return 1;
}
int main()
{
	scanf("%d%d",&n,&m);
	int l=1,r=0;
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	sort(a+1,a+n+1);//將點的位置從小到大排序 
	r=a[n];
	while(l<=r){//二分答案 
		int mid=(l+r)>>1;
		if(check(mid))
			r=mid-1;
		else l=mid+1;
	}
	printf("%d",l);//要輸出左邊界,輸出右邊界會導致錯誤的(原因可以自己手動模擬一下) 
    return 0;
}

完結撒fa~