0
点赞
收藏
分享

微信扫一扫

NOIP2010导弹拦截

NOIP2010导弹拦截icon-default.png?t=M0H8https://ac.nowcoder.com/acm/problem/16601思路:当只有一套导弹拦截系统的时候,很容易想到,答案就是该拦截系统到所有导弹的距离的最大值的平方。

现在有两套系统,怎么求这个平方和呢,我们可以枚举,每个系统都有n种半径的选择,两层for循环,保证两个系统可以覆盖所有导弹,时间复杂度是n^2,题中n可以到100000,会超时。

采用贪心策略。

两套拦截系统分别记为拦截系统1和拦截系统2。考虑到最后求的是半径的平方和,我们中间求距离的平方,而不是距离。先来研究拦截系统1,根据导弹到拦截系统1的距离平方,将各个导弹进行排序。第一步,我们让拦截系统1拦截全部的导弹n枚,拦截系统2的半径为0。第二步,我们让拦截系统1的半径降低一点,降低到只能拦截n-1枚,剩下的一枚我们给拦截系统2去拦截,拦截系统2的半径更新,计算此时的半径平方和。第三步,我们再次降低拦截系统1的半径,拦截n-2枚,拦截系统2又增加了一枚需要拦截的导弹,(拦截系统2需要拦截2枚导弹),更新拦截系统2的系统,计算此时的半径平方和。此后每一步,我们减少1枚拦截系统1的导弹,减少的这枚给拦截系统2去拦截。最后,拦截系统2拦截所有导弹,拦截系统1拦截0枚导弹。可以实现扫一遍就找到答案(前提是事先选个拦截系统,依据导弹到该拦截系统的距离平方和,对所有导弹排序)。

根据上面的叙述,我们发现,拦截系统1和拦截系统2的地位等同,第一步和最后一步是对称的。整个过程中,我们需要导弹到两个系统的距离平方和,可以实现计算出来。

对于排序,使用C++内置的sort方法,sort(a,s,e[,cmp]),注意该函数排序的区间是数组a的[s,e)区间,左闭右开,可以自定义cmp比较函数,默认从小到大升序排序。

下面是我个人写的代码,事实上,可以结构体node里不需要成员x和y表示该导弹的坐标,整个过程只要距离即可。另外,在使用C++时,注意不要忘记了struct这个关键词,有时候比内置的map、pair类型好用(具体情况具体分析,有这个意识就可以了)。

另注:本题不考虑最后所有导弹都由拦截系统2拦截这种情况的话,也可以通过。即删去

maxjuli2 = max(a[n].juli2, maxjuli2);//拦截导弹2的半径需要多少
    minjuli = min(minjuli, maxjuli2);//拦截导弹2全部拦截,是否优于之前的情况
    cout << minjuli;

也可以通过。

代码如下

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
struct node {
int x;
int y;
int juli1;
int juli2;
};
int distance(struct node a, struct node b) {
return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
}
bool compare(struct node a, struct node b) {
return a.juli1 > b.juli1;
}
struct node lanjie1, lanjie2, a[1000010];
int n;
int main() {
cin >> lanjie1.x >> lanjie1.y >> lanjie2.x >> lanjie2.y >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i].x >> a[i].y;//输入的时候查重不好操作,增加复杂度
a[i].juli1 = distance(lanjie1, a[i]);
a[i].juli2 = distance(lanjie2, a[i]);
}
sort(a+1, a + n + 1,compare);//升序排列
int ans = -1;
int minjuli = a[1].juli1;//最小距离设置为拦截导弹1的半径
int maxjuli2 = -1;
if (n == 1) {
cout << min(a[1].juli2, minjuli);
return 0;
}
for (int i = 2; i <= n; i++) {//每轮循环,拦截导弹1拦截半径是a[i].juli1
//加入a[i-1]这枚导弹到拦截导弹2中
maxjuli2 = max(a[i - 1].juli2, maxjuli2);//拦截导弹2的半径需要多少
minjuli = min(minjuli, maxjuli2 + a[i].juli1);//
}
maxjuli2 = max(a[n].juli2, maxjuli2);//拦截导弹2的半径需要多少
minjuli = min(minjuli, maxjuli2);//拦截导弹2全部拦截,是否优于之前的情况
cout << minjuli;
return 0;
}
举报

相关推荐

0 条评论