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;
}
分类:
CSP-J复赛真题解析
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现