线上OJ:
一本通:http://ybt.ssoier.cn:8088/problem_show.php?pid=1951
核心思想:
1、我们把导弹分为区间1和区间2来看。1#拦截区间1,2#拦截区间2。
2、则:1#的拦截半径为区间1 中 最远的导弹,而2#的拦截半径为 区间2 中 最远 的导弹。
3、所以本题可以 枚举所有区间 的可能性,并计算每种区间划分下的 r 1 2 + r 2 2 r1^2+ r2^2 r12+r22
4、最后求出极小值.
5、枚举区间之前,我们先考虑区间1包含了所有导弹,区间2一个都不包含
6、然后把 区间1 里面的导弹按照 从远到近的顺序 一个一个漏出去,每放出去一个,更新一次 r 1 2 r1^2 r12
7、区间2 则考虑 囊括漏出来的导弹,如果需要更新拦截半径才能囊括,则更新 r 2 2 r2^2 r22
假设某导弹 a[i]的坐标为(ax, ay);
1# 拦截系统坐标为(x1, y1);
2# 拦截系统坐标为(x2, y2);
则 a[i]到两个防御系统的“距离的平方和”分别为
d 1 = ( a x − x 1 ) 2 + ( a y − y 1 ) 2 d1 = (ax− x1)^2+(ay−y1)^2 d1=(ax−x1)2+(ay−y1)2
d 2 = ( a x − x 2 ) 2 + ( a y − y 2 ) 2 d2 = (ax− x2)^2+(ay−y2)^2 d2=(ax−x2)2+(ay−y2)2
如果a[i]是1#拦截系统的最大范围,a[j]是2#拦截系统的最大范围,(由于拦截半径的平方和就是最远导弹和拦截系统的距离的平方和),所以
1#拦截系统工作半径的平方和: r 1 2 = a [ i ] . d 1 = ( a [ i ] . x − x 1 ) 2 + ( a [ i ] . y − y 1 ) 2 r1^2 = a[i].d1 = (a[i].x− x1)^2+(a[i].y−y1)^2 r12=a[i].d1=(a[i].x−x1)2+(a[i].y−y1)2
2#拦截系统工作半径的平方和: r 2 2 = a [ j ] . d 2 = ( a [ j ] . x − x 1 ) 2 + ( a [ j ] . y − y 1 ) 2 r2^2 = a[j].d2 = (a[j].x− x1)^2+(a[j].y−y1)^2 r22=a[j].d2=(a[j].x−x1)2+(a[j].y−y1)2
故,本题所求的其实是在导弹被全覆盖情况下 a [ i ] . d 1 + a [ j ] . d 2 a[i].d1 + a[j].d2 a[i].d1+a[j].d2 的最小值。
具体理解可参见下图
题解代码:
#include <bits/stdc++.h>
#define INF 1e9
using namespace std;const int N = 100005;struct Node
{int d1, d2; // d1和d2 分别记录该导弹到1#和2#拦截系统的“距离的平方和”;
};
Node a[N]; // a[i]表示第i个导弹bool cmp(Node a, Node b) // 先根据导弹与1#拦截系统的距离进行升序排序
{return a.d1 < b.d1;
}int main()
{int x1, y1, x2, y2, n;scanf("%d %d %d %d %d", &x1, &y1, &x2, &y2, &n);for(int i = 1; i <= n; i++) // 读入每个导弹的坐标,并计算导弹与1#和2#拦截系统的“距离的平方和”{int ax, ay;scanf("%d %d", &ax, &ay);a[i].d1 = (ax - x1)*(ax - x1) + (ay - y1)*(ay - y1);a[i].d2 = (ax - x2)*(ax - x2) + (ay - y2)*(ay - y2);}sort(a + 1, a + 1 + n, cmp); // 根据导弹与1#拦截系统的距离进行升序排序// 从“1#拦截所有,2#拦截0个”开始枚举int r22 = 0; // r22表示r2^2,记录2#拦截系统最大工作半径的平方和。由于初始2#拦截0个,所以r22初始化为0int ans = a[n].d1; // 记录 r1^2 + r2^2 的最小值。 r1^2就是a[i].d1,r2^2就是r22。由于初始时1#拦截所有,所以a[n].d1即为结果for(int i = n; i >= 1; i--) // 2#拦截系统专拦截1#的漏网之鱼,1#每漏掉一个,2#就要重新计算最大工作半径的平方和,将其包含进去。{r22 = max(r22, a[i].d2);ans = min(ans, a[i-1].d1 + r22); // a[0].d1 = 0}printf("%d\n", ans);return 0;
}