题解 P1158 【导弹拦截】
LightningUZ · · 题解
马上要CSP了,赶快来做点真题
做到了这个题。然后,我太蕉♂急了,第一反应:对于每个点,去找最近的系统管。
刷刷写出代码,信心满满的交上去,完美的只有
然后我来讲一下这个算法为什么不对,顺便提醒一下大家,在做
是这样的:有一些点,如果每个就近选,就会用更多的系统,导致答案分散,用大量的花费完成少量的任务。更优的解法是,一个系统虽然花费的更多,但是一次珂以管理更多导弹。
这句话有点难懂,但是看图就明白了。
图中,
然后按照刚刚的“就近原则”,应该是
实际上,只要
这种算法失败的原因,就是因为把原本一个系统就能解决的事情,交给了两个系统。
那么正确的算法又是什么呢。
首先,导弹显然是无序的,根据常年经验和数据我们意识到要排序。
然后我们意识到,我们要把这些导弹分成两个部分,不一定非空,一部分给
然后我们灵机一动,我们按照到
然后枚举断点找最小即珂。
代码:
#include <bits/stdc++.h>
using namespace std;
namespace Flandre_Scarlet
{
#define N 155555
#define F(i,l,r) for(int i=l;i<=r;++i)
#define D(i,r,l) for(int i=r;i>=l;--i)
#define Fs(i,l,r,c) for(int i=l;i<=r;c)
#define Ds(i,r,l,c) for(int i=r;i>=l;c)
#define Tra(i,u) for(int i=G.Start(u),__v=G.To(i);~i;i=G.Next(i),__v=G.To(i))
#define MEM(x,a) memset(x,a,sizeof(x))
#define FK(x) MEM(x,0)
struct node{int x,y;}a[N];
int n;
void R1(int &x)
{
x=0;char c=getchar();int f=1;
while(c<'0' or c>'9') f=(c=='-')?-1:1,c=getchar();
while(c>='0' and c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
x=(f==1)?x:-x;
}
void Input()
{
R1(a[1].x),R1(a[1].y),R1(a[2].x),R1(a[2].y);
R1(n);
F(i,3,n+2) R1(a[i].x),R1(a[i].y);
}
int dis2(node a,node b)
{
return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
bool cmp(node x,node y)
{
return dis2(x,a[1])<dis2(y,a[1]);
}
int dis[N];
void Soviet()
{
sort(a+3,a+n+3,cmp);
D(i,n+2,3)
{
dis[i]=max(dis[i+1],dis2(a[i],a[2]));
}
int ans=0x7f7f7f7f;
F(i,3,n+2)
{
int r1=dis2(a[i],a[1]);
int r2=dis[i+1];
ans=min(ans,r1+r2);
}
printf("%d\n",ans);
}
#define Flan void
Flan IsMyWife()
{
Input();
Soviet();
}
}
int main()
{
Flandre_Scarlet::IsMyWife();
getchar();getchar();
return 0;
}