P1158 导弹拦截
P1158 导弹拦截
题解
这不是一道简单的贪心,他还要枚举
我们首先要计算出导弹距离距离两个拦截系统分别的距离
then,假设由一个拦截系统把它们全部拦截,然后逐一枚举导弹
如果另一个拦截系统距离它更近我们显然是要更新的
r1 表示拦截系统1的半径平方
r2 表示拦截系统2的半径平方
我们假设第一个拦截系统把它们全部拦截
按照导弹与拦截系统1 的距离从小到大排序,然后从大到小枚举
这样距离拦截系统1最远的导弹就被放在了最后面,但是不确定距离拦截系统2的距离
(其实这样sort下来就相当于维护了一个前缀和,a[ i ].chang1表示拦截前 i 个导弹需要的最小 r1)
那么 r1 一开始一定是等于 a[ n ].chang1
从大到小枚举:
假设现在有导弹 i ,它被拦截系统2拦截(前提是超出 r2 的拦截范围),那么前 i 个导弹一定都是被拦截系统2拦截(否则的话,根本就不会更新啊),那么剩下的导弹被拦截系统1 拦截,计算出此时的结果,与先前的结果比较,求解一个最小值
最后还要比较一下更新 ans 和 r1 ,单个拦截更优还是两个一起拦截更优
代码
#include<iostream> #include<cstdio> #include<algorithm> #include<string> #include<cstring> #include<cmath> #include<bits/stdc++.h> using namespace std; int x1,yi,x2,y2,x,y,n; int r1,r2,ans=1e9+6; struct node { int chang1,chang2; }a[100001]; bool cmp(node x,node y) { return x.chang1 <y.chang1 ; } int main() { scanf("%d%d%d%d%d",&x1,&yi,&x2,&y2,&n); for(int i=1;i<=n;i++) { scanf("%d%d",&x,&y); a[i].chang1 =(x-x1)*(x-x1)+(y-yi)*(y-yi); a[i].chang2 =(x-x2)*(x-x2)+(y-y2)*(y-y2); } sort(a+1,a+n+1,cmp); r1=a[n].chang1 ; for(int i=n-1;i>=1;i--) { if(r2<a[i+1].chang2 ) r2=a[i+1].chang2 ; ans=min(ans,a[i].chang1 +r2); } printf("%d",min(ans,r1)); }