我的做法是枚举所有导弹,并算出坐标为 (x1,y1) 的导弹拦截系统在 拦截现在的导弹后能拦截哪些导弹,剩下的导弹由坐标为 (x2,y2) 的导弹拦截系统来处理,并更新最小代价。
#include<bits/stdc++.h>
using namespace std;
const int maxn=100004;
int n,p,res=0x7fffffff;
struct point{
int x,y;
bool operator < (const point &comp) const{
return x<comp.x;
}
}fir,sec,s[maxn],s1[maxn],s2[maxn];
map < point,bool > vis;
const int _min(const int &a,const int &b){
return a<b?a:b;
}
const int dis(const point &a,const point &b){
return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
bool cmp1(const point &a,const point &b){ return dis(a,fir)<dis(b,fir);}
bool cmp2(const point &a,const point &b){ return dis(a,sec)>dis(b,sec);}
int main(){
scanf("%d %d %d %d",&fir.x,&fir.y,&sec.x,&sec.y);
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d %d",&s[i].x,&s[i].y);
s1[i].x=s2[i].x=s[i].x;
s1[i].y=s2[i].y=s[i].y;
}
//把导弹按离(x1,y1)距离由近到远排序
sort(s1,s1+n,cmp1);
//把导弹按离(x2,y2)距离由远到近排序
sort(s2,s2+n,cmp2);
res=dis(s2[0],sec);
//位于(x1,y1)的拦截系统工作范围渐渐扩大
for(int i=0;i<n;i++){
if(vis[s1[i]])
continue;
//d1,d2分别为位于(x1,y1),(x2,y2)的拦截系统工作范围
int d1=dis(s1[i],fir),d2=0;
for(int j=i;j<n&&d1==dis(s1[j],fir);j++)
vis[s1[j]]=1; //把与当前导弹共圆的导弹也能被拦截
while(vis[s2[p]]) //求出没有被拦截并离(x2,y2)最远的导弹
++p;
if(p<n) //如果这个导弹存在
d2=dis(s2[p],sec);
//更新结果
res=_min(res,d1+d2);
}
printf("%d",res);
return 0;
}