CSP历年复赛题-P1158 [NOIP2010 普及组] 导弹拦截

原题链接:https://www.luogu.com.cn/problem/P1158

题意解读:用两套拦截系统拦截全部导弹,计算最小的拦截系统半径平方和。

解题思路:

错误的思路:

  枚举每一个导弹,计算到两套系统的距离,距离谁近就归属哪套系统管。

  错误原因:

  举个反例,假设只有两个导弹,

  第一个导弹,距离两个系统s1,s2,s1 < s2,归属到系统1,系统1的半径至少是s1

  第二个导弹,距离两个系统d1,d2,d2 < d1,d1 < s1,

    如果归属到系统2,则系统2的半径至少是d2,这样结果是s1 + d2

    而如果归属到系统1,则系统2的半径可以是0,系统1的半径最小仍是s1,这样结果是s1,显然结果更小。    

正确的思路:

  先将所有导弹都归属给系统1,这样系统1的半径至少是所有导弹中距离系统1最远的

  再逐步缩小系统1的半径,漏出的导弹归属给系统2,每漏出一个,更新一次系统1的最小半径,系统2的更小半径,再计算一次结果,取最小值

  编程实现时,

  可以先将所有导弹与系统1、系统2的距离都计算出来,再按照与系统1的距离从大到小排序

  枚举每一个导弹的作为漏出系统1,归属给系统2的,更新枚举过程中的系统1、系统2最小半径,计算结果,取最小值

  注意:以上提到的距离、半径都是平方之后的结果。

100分代码:

#include <bits/stdc++.h>
using namespace std;

const int N = 100005;
struct node
{
    int s1, s2;
};
node w[N];
int X1, Y1, X2, Y2, n;

bool cmp(node a, node b)
{
    return a.s1 > b.s1;
}

int main()
{
    
    cin >> X1 >> Y1 >> X2 >> Y2 >> n;
    int x, y;
    for(int i = 1; i <= n; i++)
    {
        cin >> x >> y;
        w[i].s1 = (x - X1) * (x - X1) + (y - Y1) * (y - Y1);
        w[i].s2 = (x - X2) * (x - X2) + (y - Y2) * (y - Y2);
    }
    sort(w + 1, w + n + 1, cmp);

    int r1 = 0; //拦截系统1的最小半径
    int r2 = 0; //拦截系统2的最小半径
    int ans = INT_MAX; //r1 + r2
    for(int i = 0; i <= n; i++) //注意从0开始可以处理一开始全归属系统1
    {
        r1 = w[i+1].s1; //把i归属给拦截系统2,拦截系统1的半径更新
        r2 = max(r2, w[i].s2); //拦截系统2的最小半径更新,每次归属的导弹取较大值
        ans = min(ans, r1 + r2);
    }
    cout << ans;

    return 0;
}

 

posted @ 2024-05-28 17:44  五月江城  阅读(114)  评论(0编辑  收藏  举报