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));
    
}

 

posted @ 2019-06-15 20:55  晔子  阅读(223)  评论(1编辑  收藏  举报