noip2010导弹拦截

洛谷的题。。。在此省略题目。。。这题还是比较水的。。。

开始想用前缀s1和与后缀s2和做。。。后来发现是不是。。。没办法还是自己太菜了。。。

其实这道题很简单。。。就是给两个点,然后一系列的点,问以这两个点为圆心的半径平方后之和最小是多少。。。我们可以用结构体排序做。。。用一个结构体数组a[i].s1和a[i].s2如下:

struct dr{
   int x,y,s1,s2;
}a[100050];

a[i].s1和a[i].s2表示i点到s1和s2的距离

然后再结构体按照a[i].s1降序排序就好了,这样排序处来,是以a[i].s1降序排序的,那么从1->n中间i数的含义是,前面的i-1个点是用第二个点打,而i->n由于降序排序,第一个点打到第i个点,那么后面都能被打到,而前1到i-1个点,需要求一个a[i].s2最大值然后与a[i].s1加起来。这样的意思是我第一点最远打到i点。这样从1-n+1扫一遍即可。。。n+1表示。。。第一个点压根不打。。。

最后注意初始化。。。以及结构排序需要写一个结构体排序的cmp函数

bool cmp(dr a,dr b){
    return a.s1 > b.s1;
}

最后AC代码

#include
#include
#include
#include
using namespace std;
struct dr{
   int x,y,s1,s2;
}a[100050];
bool cmp(dr a,dr b){
    return a.s1 > b.s1;
}
int main(){
   int n,x1,x2,y1,y2;
   while (~scanf("%d%d%d%d",&x1,&y1,&x2,&y2)){
   scanf("%d",&n);
   for (int i=1;i<=n;i++){
     scanf("%d%d",&a[i].x,&a[i].y);
     a[i].s1=(a[i].x-x1)*(a[i].x-x1)+(a[i].y-y1)*(a[i].y-y1);
     a[i].s2=(a[i].x-x2)*(a[i].x-x2)+(a[i].y-y2)*(a[i].y-y2);
   }
   sort(a+1,a+1+n,cmp);
   a[0].s2=0;
   a[n+1].s1=0;
   int r=0;
   int ans=1000000000;
   for (int i=1;i<=n+1;i++){
     r=max(r,a[i-1].s2);
     ans=min(ans,a[i].s1+r);
   }
   printf("%d\n",ans);
   }
   return 0;
}


你可能感兴趣的:(noip2010导弹拦截)