【RACKET】导弹拦截

【Problem description】

  经过11年的韬光养晦,某国研发出了一种新的导弹拦截系统,凡是与它的距离不超过其工作半径的导弹都能够被它成功拦截。当工作半径为0  时,则能够拦截与它位置恰好相同的导弹。但该导弹拦截系统也存在这样的缺陷:每套系统每天只能设定一次工作半径。而当天的使用代价,就是所有系统工作半径的平方和。
  某天,雷达捕捉到敌国的导弹来袭。由于该系统尚处于试验阶段,所以只有两套系统投入工作。如果现在的要求是拦截所有的导弹,请计算这一天的最小使用代价。

【Input format】

  第一行包含4 个整数x1、y1、x2、y2,每两个整数之间用一个空格隔开,表示这两套导弹拦截系统的坐标分别为(x1, y1)、(x2, y2)。
  第二行包含1 个整数N,表示有N 颗导弹。接下来N 行,每行两个整数x、y,中间用一个空格隔开,表示一颗导弹的坐标(x, y)。不同导弹的坐标可能相同。

【Output format】

  输出只有一行,包含一个整数,即当天的最小使用代价。

提示

两个点(x1, y1)、(x2, y2)之间距离的平方是(x1- x2)^2+(y1-y2)^2。
  两套系统工作半径r1、r2 的平方和,是指r1、r2 分别取平方后再求和,即r1^2+r2^2。

【Algorithm design】

Enumeration & sort

【Problem analysis】

O(n)

首先把每一个点到两个系统的距离平方算出来

按一般套路来

枚举系统1打哪几个 系统2打哪几个

这样的话每次要把系统1范围内距其最远的算出来

而且如果系统1范围内打到的导弹要求半径已经能打到系统2分配的任务

系统2就没必要打了

出现了冗余计算

这里可以直接结构体快排

把距系统1的距离排列

则每次只要算范围内最后一个的距离

前面的就都能打到

系统二一个一个收下即可

Cmp条件:

bool cmp(node p,node q)

{

   if(p.d[0]!=q.d[0])return p.d[0]<q.d[0];

   else if(p.d[1]!=q.d[1])return p.d[1]>q.d[1];

   else return p.id<q.id;

}

因为发现距离系统1相等而位置不一的导弹到系统2的距离不等

所以优先把距系统2近的放在范围外

留给系统2收下

第一次TLE是每次都把系统2的范围枚举算一遍 其实是出现了冗余

每次只要把系统1扔出来的一个算入即可

第二次WA是距离的处理位置放错了导致意义不明

【Source code】

#include <bits/stdc++.h>

#define F(i,j,k) for(int i=j;i<=k;i++)

#define D(i,j,k) for(int i=j;i>=k;i--)

#define MAXN 99999999

using namespace std;

struct node

{

   int rx,ry,d[2],id;

}rac[100001];//d[0],d[1]分别表示到系统1,2距离

int x[2],y[2],r[2];

int n,ans=MAXN;

int dis(int a,int b,int c,int d)

{

   return (a-c)*(a-c)+(b-d)*(b-d);

}//距离公式

bool cmp(node p,node q)

{

   if(p.d[0]!=q.d[0])return p.d[0]<q.d[0];

   else if(p.d[1]!=q.d[1])return p.d[1]>q.d[1];

   else return p.id<q.id;

}//前文提过了

void readp()

{

   F(i,0,1)

      cin>>x[i]>>y[i];

   cin>>n;

   F(i,1,n)

   {

      cin>>rac[i].rx>>rac[i].ry;

      F(j,0,1)rac[i].d[j]=dis(rac[i].rx,rac[i].ry,x[j],y[j]);

      rac[i].id=i;

   }//储存距离

   sort(rac+1,rac+n+1,cmp);//排序

   return;

}

void work()

{

   int cnt=0;

   D(i,n,0)

   {

      if(i!=n)cnt=max(rac[i+1].d[1],cnt);

//一打不完所有的就要加上系统二

      if(i!=0)cnt+=rac[i].d[0];

//二打不完所有的就算上一的最大值

      ans=min(ans,cnt);

//打擂台取最小值

      cnt-=rac[i].d[0];

//还原系统二半径平方

   }     

   return;

}

void write()

{

   cout<<ans<<endl;

   return;

}

int main()

{

   freopen("test.in","r",stdin);

   freopen("test.out","w",stdout);

   std::ios::sync_with_stdio(false);

   readp();

   work();

   write();

   return 0;

}

以上、

猜你喜欢

转载自www.cnblogs.com/qswx/p/9155633.html