导弹拦截

OJ地址:
https://www.luogu.org/problemnew/show/P1158
http://codevs.cn/problem/1128/
 
题目描述 Description

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

数据范围
对于10%的数据,N = 1
对于20%的数据,1 ≤ N ≤ 2
对于40%的数据,1 ≤ N ≤ 100
对于70%的数据,1 ≤ N ≤ 1000
对于100%的数据,1 ≤ N ≤ 100000,且所有坐标分量的绝对值都不超过1000。

输入描述 Input Description

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

输出描述 Output Description

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

样例输入 Sample Input

0 0 10 0
2
-3 3
10 0

样例输出 Sample Output

18

数据范围及提示 Data Size & Hint

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

【样例说明】

样例1中要拦截所有导弹,在满足最小使用代价的前提下,两套系统工作半径的平方分别为18和0。

算法分析

参考

https://blog.csdn.net/yuyanggo/article/details/48739029

http://hzwer.com/44.html

假设两个导弹系统为p1、p2,那么我们可以通过枚举两个导弹系统的半径,寻找最小值消耗值。

导弹系统的半径必然是系统所在位置与某一导弹的连线,基于此,p1的可能半径就只有n种,现在的问题就是枚举p1的半径之后,如何得到p2的半径呢?

我们把所有的导弹按其坐标点到p1的距离从大到小进行排序,若选择 k 号点到p1的距离作为半径,那么k点之后的点都能被p1击落。而k点之前的点p1是无法拦截的,只能由p2击落,于是,p2的半径即为前 k-1个点到 p2 的最大半径。
这道题有一个难点:如何寻找“前 k-1个点到 p2 的最大半径”。若是每当确定k点位置后,再来一次循环去寻找前k-1个点到p2的最大距离,那么整个算法的时间复杂度将会达到N^2级别,提交OJ时会超时。如何解决呢?

其实,上述算法描述中已经隐约暗示了解决方式。上述算法描述中,为何非要从距离p1最远的那个点开始枚举k呢?从距离p1最远的点开始枚举,一开始的时候p1负责拦截所有导弹,p2是不拦截任何导弹的,也就是p2的工作半径是0.然后随着枚举的继续,k每次挪动一个位置,p2拦截的导弹也会增多一枚。仅仅增多一枚导弹,很容易判断出新状态下p2拦截区域的最大工作半径。所以,必须要让p2一开始是不拦截任何导弹,然后p2拦截的导弹数量逐渐增加。

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. struct obj
  4. {
  5. int d1,d2; //d1和d2分别表示某一个导弹距离p1和p2的距离的平方
  6. };
  7. int cmp(const void *a,const void *b)//按照D[i].d1从大到小排序
  8. {
  9. struct obj *x,*y;
  10. x=(struct obj*)a;
  11. y=(struct obj*)b;
  12. return y->d1 - x->d1;
  13. }
  14. int main(int argc, char *argv[])
  15. {
  16. int x1,y1,x2,y2,x,y,N;
  17. struct obj D[];//存储所有的导弹
  18. int i,j;
  19. int r1,r2,cost,minCost=-;
  20.  
  21. scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
  22. scanf("%d",&N);
  23. for(i=;i<N;i++)
  24. {
  25. scanf("%d%d",&x,&y);
  26. D[i].d1=(x-x1)*(x-x1)+(y-y1)*(y-y1);
  27. D[i].d2=(x-x2)*(x-x2)+(y-y2)*(y-y2);
  28. }
  29.  
  30. qsort(D,N,sizeof(D[]),cmp);//按照D[i].d1从大到小排序
  31. /*for(i=0;i<N;i++)
  32. printf("%d %d\n",D[i].d1,D[i].d2);*/
  33.  
  34. //第一种极限情况:所有导弹均由p1系统拦截
  35. r2=;
  36. r1=D[].d1;
  37. minCost=r1+r2;
  38.  
  39. r2=D[].d2;
  40. for(i=;i<N;i++)//从D[0]~D[i-1]由p2拦截,D[i]~D[n-1]由p1拦截
  41. {
  42. r1=D[i].d1;
  43. if(r2<D[i-].d2) r2=D[i-].d2;
  44. cost=r1+r2;
  45. if(cost<minCost) minCost=cost;
  46. }
  47.  
  48. //第二种极限情况:所有导弹均由p2拦截
  49. r1=;
  50. if(r2<D[N-].d2) r2=D[N-].d2;
  51. cost=r1+r2;
  52. if(cost<minCost) minCost=cost;
  53.  
  54. printf("%d\n",minCost);
  55. return ;
  56. }

下面这个代码比较简洁,可以参考一下。

设拦截系统为 a , b

按照导弹到其中一个拦截系统 a 的距离排序,将离 a 最近的 i 个导弹都交给 a ,其余给 b

倒序枚举断点,每次更新答案

  1. #include<cstdio>
  2. #include<iostream>
  3. #include<algorithm>
  4. using namespace std;
  5.  
  6. #define inf 1000000000
  7. #define ll long long
  8.  
  9. struct data
  10. {
  11. int x,y,s1,s2;
  12. }a[];
  13.  
  14. int n,x1,y1,x2,y2;
  15. int mn=inf;
  16.  
  17. bool cmp(data a,data b)//结构体比较函数,可以理解为定义小于号,即a.s1<b.s1时return 1 否则return 0
  18. {
  19. return a.s1<b.s1;
  20. }
  21. int main()
  22. {
  23. scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
  24. scanf("%d",&n);
  25. for(int i=;i<=n;i++)
  26. {
  27. scanf("%d%d",&a[i].x,&a[i].y);
  28. a[i].s1=(a[i].x-x1)*(a[i].x-x1)+(a[i].y-y1)*(a[i].y-y1);//计算距离。注意:这里没有开平方
  29. a[i].s2=(a[i].x-x2)*(a[i].x-x2)+(a[i].y-y2)*(a[i].y-y2);
  30. }
  31. sort(a+,a+n+,cmp);//对a[1]~a[n]进行排序,按照a[i].s1升序排序
  32.  
  33. int rb=;
  34. a[n+].s2=;
  35. for(int i=n;i>;i--)//从离a最远的导弹开始枚举
  36. {
  37. rb=max(a[i+].s2,rb);//将i+1号导弹交给系统b,更新系统b的半径
  38. mn=min(mn,a[i].s1+rb);//更新答案
  39. }
  40.  
  41. //一种极限情况
  42. rb=max(a[].s2,rb);//将所有导弹交给系统b,更新系统b的半径
  43. mn=min(mn,+rb);//更新答案
  44.  
  45. printf("%d",mn);
  46. return ;
  47. }

NOIP2010普及组 导弹拦截的更多相关文章

  1. 求最长子序列(非连续)的STL方法 - 洛谷P1020 [NOIP1999 普及组] 导弹拦截

    先给出例题:P1020 [NOIP1999 普及组] 导弹拦截 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 大佬题解:P1020 [NOIP1999 普及组] 导弹拦截 - 洛谷 ...

  2. 洛谷 P1020 [NOIP1999 普及组] 导弹拦截

    Coidng #include <iostream> #include <algorithm> #include <cstring> #include <ve ...

  3. NOIP2010普及组题解 -SilverN

    三国游戏 题目内容不放了 由于电脑总是会拆掉最大的组合,所以玩家最多只能得到数值第二大的组合 那么找出第二大的组合就行了 #include<iostream> #include<cs ...

  4. [NOIP2010] 普及组

    三国游戏 题目内容不放了 由于电脑总是会拆掉最大的组合,所以玩家最多只能得到数值第二大的组合 那么找出第二大的组合就行了 #include<iostream> #include<cs ...

  5. NOIP2010普及组 三国游戏 -SilverN

    #include<iostream> #include<cstdio> #include<algorithm> #include<cmath> usin ...

  6. NOIP2010普及组T4 三国游戏——S.B.S.

    题目描述 小涵很喜欢电脑游戏,这些天他正在玩一个叫做<三国>的游戏. 在游戏中,小涵和计算机各执一方,组建各自的军队进行对战.游戏中共有 N 位武将(N为偶数且不小于 4),任意两个武将之 ...

  7. NOIP2010普及组T3 接水问题 ——S.B.S.

    题目描述 学校里有一个水房,水房里一共装有 m 个龙头可供同学们打开水,每个龙头每秒钟的 供水量相等,均为 1. 现在有 n 名同学准备接水,他们的初始接水顺序已经确定.将这些同学按接水顺序从 1到 ...

  8. 接水问题【NOIP2010普及组】优先队列

    题目描述 学校里有一个水房,水房里一共装有 m 个龙头可供同学们打开水,每个龙头每秒钟的供水量相等,均为 1. 现在有 n 名同学准备接水,他们的初始接水顺序已经确定.将这些同学按接水顺序从 1到 n ...

  9. NOIP2010普及组 三国游戏

    题目OJ地址 http://codevs.cn/problem/1129/ https://www.luogu.org/problemnew/show/P1199 题目描述 Description 小 ...

随机推荐

  1. sql语句start with connect by prior语法解析

    prior分两种放法: 1 放在子节点端 表示start with 指定的节点作为根节点,按照从上到下的顺序遍历 2 放在父节点端 表示start with指定的节点作为最底层节点,按照从下到上的顺序 ...

  2. mysql 分区 1526错误

    mysql 分区 原文:http://fyzjhh.blog.163.com/blog/static/1694442262012544429953/ 参考:https://bugs.mysql.com ...

  3. --mysql 导出数据时, 数字类型的列如果位数过长,变为科学计数法问题

    --mysql 导出数据时, 数字类型的列如果位数过长,变为科学计数法问题在字段前加上\t即可select concat('\t',a.IDCARD_NO) from xxx a

  4. Binder原理

    --摘自<android插件化开发指南> 1.Binder分为Client和Server两个进程: client和server是相对的.谁发消息,谁就是client:谁接收消息,谁就是se ...

  5. 网络编程-线程-3、通过继承Thread类创建线程

    知识点:之前第一节介绍创建线程的方法是:通过threading.Thread(target=函数名不要加括号)创建一个对象,通过对象调用start方法创建并启动线程:                  ...

  6. angular7一周学习

    ng new xxx 创建一个项目 ng serve --open 执行一个项目 angular 使用socket.io 报错 找到polyfills.ts添加 (window as any).glo ...

  7. byte ---> hex String

    public static String byte2HexString(byte[] b){ String ret = ""; ;i<b.lenght;i++){ Strin ...

  8. vue中的jsx

    一.配置文件package.json { "name": "vuetest", "version": "1.0.0", ...

  9. 论文泛读:Click Fraud Detection: Adversarial Pattern Recognition over 5 Years at Microsoft

    这篇论文非常适合工业界的人(比如我)去读,有很多的借鉴意义. 强烈建议自己去读. title:五年微软经验的点击欺诈检测 摘要:1.微软很厉害.2.本文描述了大规模数据挖掘所面临的独特挑战.解决这一问 ...

  10. 在Windows 操作系统中, MySql 如何设置, 允许表名支持大小写

    一般在网上会说明 修改my.ini文件的  lower_case_table_names = 0 参照: http://www.linuxidc.com/Linux/2013-04/82719.htm ...