题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=4145
题目大意:
给你2个大炮和一些敌人,每个大炮的攻击半径为r,A大炮和B大炮的攻击范围分别为r1和r2。问怎样才能使r1*r1 + r2*r2最小。。。
解题思路:
这道题刚开始想错了,以为枚举每个敌人,比较它到2个大炮的距离,如果距离A近,则把这个距离与上个距离A近的敌人的距离比较,取较大者。反之同理处理B。这样就得到A和B炮的半径,进而得到答案。但是这样是错的。比如AB距离为100,他们中点旁边各有1个敌人,根据这种思路得到的距离为49*49 + 49 * 49 = 4802,而如果只用A,则只需要51 * 51 = 2601.所以这种思路是错误的。
正确思路应该是:
将所有敌人距离A的距离从大到小排序,然后枚举A的半径,则B的半径就是A无法覆盖的点中距离B最远的距离。然后用一个变量维护A和B距离的最小值即可。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 100010
struct enemy
{
int x, y, da, db;
}p[N], c1, c2;
bool cmp(enemy a, enemy b)
{
return a.da < b.da;
}
int dist(enemy a, enemy b)
{
return ((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
int main()
{
int ncase;
int num;
int ans, res, onlyb;
scanf("%d", &ncase);
while(ncase--)
{
scanf("%d%d%d%d", &c1.x, &c1.y, &c2.x, &c2.y);
scanf("%d", &num);
for(int i = 0; i < num; ++i)
{
scanf("%d%d", &p[i].x, &p[i].y);
p[i].da = dist(c1, p[i]);
p[i].db = dist(c2, p[i]);
}
sort(p, p + num, cmp);
res = p[num - 1].da; //b不用
ans = 0;
for(int i = num - 2; i >= 0; --i)
{
ans = max(ans, p[i + 1].db);
res = min(res, ans + p[i].da);
}
ans = max(ans, p[0].db);
res = min(res, ans); //a不用
printf("%d\n", res);
}
return 0;
}