首先看到题目求最小覆盖,应该可以想到是贪心类的问题
题目要求覆盖所有骨龙,首先所有骨龙都会在一段区间内被覆盖,我们可以算出每个骨龙的这段距离。
之后就是求有多少个点可以将这些区间全部覆盖,这是贪心的经典问题。
显然是先排序,以第一个点的右端点为初始值,往下遍历,如果某个左端点大于他,那么更新为当前的右端点,++ans
否则,如果当前的右端点小于他,更新为右端点,这个需要理解一下,因为我们当前的右端点并不能覆盖它,也就是这两个区间是包含关系,所以就用类似反悔的方法,把这个点的右端点设为答案。
注意double,但是这题如果按右端点排序,更加好写
#include<bits/stdc++.h> #define x first #define y second using namespace std; typedef long long ll; typedef pair<double,double> pll; const int N=2e5+10; pll p[N]; int d,n; void cal(int a,int b,int i){ p[i].x=(double)a-sqrt(double(d*d-b*b)); p[i].y=(double)a+sqrt(double(d*d-b*b)); } void work(){ sort(p+1,p+1+n); double pos=p[1].y; int ans=1; for(int i=2;i<=n;i++){ if(p[i].x>pos){ ++ans; pos=p[i].y; } else if(p[i].y<pos) pos=p[i].y; } cout<<ans<<endl; } int main(){ ios::sync_with_stdio(false); int cnt=0; while(cin>>n>>d){ if(!n&&!d) return 0; int i; int flag=0; int a,b; for(i=1;i<=n;i++){ cin>>a>>b; if(d<b||flag){ flag=1; continue; } cal(a,b,i); } cout<<"Case "<<++cnt<<":"<<" "; if(flag) cout<<-1<<endl; else{ work(); } } }