信息学奥赛一本通 1951:【10NOIP普及组】导弹拦截 | 洛谷 P1158 [NOIP 2010 普及组] 导弹拦截

【题目链接】

ybt 1951:【10NOIP普及组】导弹拦截
洛谷 P1158 NOIP 2010 普及组 导弹拦截

【题目考点】

1. 预处理+枚举

【解题思路】

第一个拦截系统的坐标为 P 1 P_1 P1,第二个拦截系统的坐标为 P 2 P_2 P2。

拦截系统可以拦截的范围是以拦截系统所在坐标为圆心的一个圆。

第一个拦截系统的拦截范围称为"第一个圆",第二个拦截系统的拦截范围称为"第二个圆。导弹所在位置为多个点。

题目所求为:使得两圆包含所有给定点的前提下,两圆半径的平方和最小。

思路上相当于不断扩大第一个圆半径,第一个圆包含了一些点,第二个圆就要包含剩下的点。
d i s ( i , j ) dis(i,j) dis(i,j)表示 i 、 j i、j i、j两点之间距离的平方。
a a a序列保存所有点,将 a a a序列按照到 P 1 P_1 P1的距离从小到大进行排序。
d p 1 i dp1_i dp1i表示第一个圆包含前 i i i个点时,半径的平方。

  • 初值: d p 1 0 = 0 dp1_0=0 dp10=0
  • 前 i i i个点中,距离 P 1 P_1 P1最远的点为 a i a_i ai,因此: d p 1 i = d i s ( a i , P 1 ) dp1_i=dis(a_i, P_1) dp1i=dis(ai,P1)。

d p 2 i dp2_i dp2i表示第二个圆包含第 i i i到第 n n n个点时,半径的平方。

  • 初值: d p 2 n + 1 = 0 dp2_{n+1}=0 dp2n+1=0
  • 第 i i i到第 n n n个点中距离 P 2 P_2 P2最远的点,可能是第 i + 1 i+1 i+1到第 n n n个点钟距离 P 2 P_2 P2最远的点,其距离的平方为 d p 2 i + 1 dp2_{i+1} dp2i+1;也可能是第 i i i个点,其距离的平方为 d i s ( a i , P 2 ) dis(a_i,P_2) dis(ai,P2),二者取较大值。因此: d p 2 i = m a x ( d p 2 i + 1 , d i s ( a i , P 2 ) ) dp2_i=max(dp2_{i+1}, dis(a_i, P_2)) dp2i=max(dp2i+1,dis(ai,P2))

枚举分割点 i i i,第1到第 i i i点被第一个圆包含,第 i + 1 i+1 i+1到第 n n n个点被第二个圆包含。 i i i最小为0,即第二个圆包含所有点。 i i i最大为 n n n,即第一个圆包含所有点。

当分割点为 i i i时,此时的代价为第一个圆的半径的平方 d p 1 i dp1_i dp1i与第二个圆半径的平方 d p 2 i + 1 dp2_{i+1} dp2i+1的加和: d p 1 i + d p 2 i + 1 dp1_i+dp2_{i+1} dp1i+dp2i+1,求所有出现的该值的最小值,即为本题的结果。

相同的思路,也可以变递推为迭代。

【题解代码】

解法1:预处理+枚举

  • 写法1:递推
cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
struct Pair
{
    int x, y;
} p1, p2, a[N]; 
int dp1[N], dp2[N];
int disSquare(Pair a, Pair b)//距离的平方 
{
    return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
bool cmp(Pair a, Pair b)
{
    return disSquare(a, p1) < disSquare(b, p1);
}
int main()
{
    int n, ans = 1e9;
    cin >> p1.x >> p1.y >> p2.x >> p2.y >> n;
    for(int i = 1; i <= n; ++i)
        cin >> a[i].x >> a[i].y;
    sort(a+1, a+1+n, cmp);
    for(int i = 1; i <= n; ++i)
    	dp1[i] = disSquare(a[i], p1);//dp1[i]:a[1]~a[i]各点到p1的最大距离 
    for(int i = n; i >= 1; --i)
    	dp2[i] = max(dp2[i+1], disSquare(a[i], p2));//dp2[i]:a[i]~a[n]各点到p2的最大距离
    for(int i = 0; i <= n; ++i)//0~i归系统1 i+1~n归系统2 
        ans = min(ans, dp1[i]+dp2[i+1]);
    cout << ans;
    return 0;
}
  • 写法2:迭代
cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
struct Pair
{
    int x, y;
} p1, p2, a[N]; 
int disSquare(Pair a, Pair b)//距离的平方 
{
    return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
bool cmp(Pair a, Pair b)
{
    return disSquare(a, p1) < disSquare(b, p1);
}
int main()
{
    int n, ans = 1e9, r1, r2 = 0;//r1, r2:系统半径的平方
    cin >> p1.x >> p1.y >> p2.x >> p2.y >> n;
    for(int i = 1; i <= n; ++i)
        cin >> a[i].x >> a[i].y;
    sort(a+1, a+1+n, cmp);
    for(int i = n; i >= 1; --i)//1~i归系统1 i+1~n归系统2 
    {
        r1 = disSquare(a[i], p1); 
        ans = min(ans, r1+r2);
        r2 = max(r2, disSquare(a[i], p2)); 
    }
    cout << min(ans, r2);//考虑全部由系统2拦截的情况 
    return 0;
}
相关推荐
lengxuenong10 分钟前
树状数组 · 信息学学习手册3-优化LIS
c++·学习·算法
fanfan_hongyun20 分钟前
【UE5.1 创建C++文件】
c++·ue5
动词ing26 分钟前
【题目练习】外观数列
算法
余额瞒着我当琳27 分钟前
C++11,发展历史浅谈,初始化列表和对象初始化,右值引用和移动语义
java·开发语言·c++·算法
suhan40 分钟前
【数据结构】六、图:4.图的遍历(深度优先算法DFS、广度优先算法BFS)
数据结构·算法·排序算法
suhan40 分钟前
【数据结构】六、图:3.十字链表、邻接多重表、边集数组
数据结构·算法·排序算法
Dola_Zou44 分钟前
工商业储能系统核心策略
算法·自动化·软件工程
Tsuki_tl1 小时前
【优选算法:双指针】——复写零题解
java·c++·算法·leetcode·数组·双指针·复写零
Rain的Java大神之路1 小时前
面了上百人,我最爱问的LeetCode 1「两数之和」:能背代码的很多,能讲清“先查后存”的没几个
java·后端·算法
程序猿编码1 小时前
不用 PyTorch!从零手写 C++ 深度学习框架,自动微分、CUDA、分布式一把搞定
c++·深度学习·大模型推理·自动微分