NOIP2010普及組 導彈攔截

導彈攔截

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

通過11 年的韜光養晦,某國研發出了一種新的導彈攔截系統,凡是與它的距離不超過其工做半徑的導彈都可以被它成功攔截。當工做半徑爲0 時,則可以攔截與它位置剛好相同的導彈。但該導彈攔截系統也存在這樣的缺陷:每套系統天天只能設定一次工做半徑。而當天的使用代價,就是全部系統工做半徑的平方和。
某天,雷達捕捉到敵國的導彈來襲。因爲該系統尚處於試驗階段,因此只有兩套系統投入工做。若是如今的要求是攔截全部的導彈,請計算這一天的最小使用代價。html

數據範圍
對於10%的數據,N = 1
對於20%的數據,1 ≤ N ≤ 2
對於40%的數據,1 ≤ N ≤ 100
對於70%的數據,1 ≤ N ≤ 1000
對於100%的數據,1 ≤ N ≤ 100000,且全部座標份量的絕對值都不超過1000。

ios

輸入描述  Input Description

第一行包含4 個整數x一、y一、x二、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 0spa

樣例輸出  Sample Output

18.net

數據範圍及提示  Data Size & Hint

兩個點(x1, y1)、(x2, y2)之間距離的平方是(x1− x2)^2+(y1−y2)^2。
兩套系統工做半徑r一、r2 的平方和,是指r一、r2 分別取平方後再求和,即r1^2+r2^2。code

【樣例說明】htm

樣例1中要攔截全部導彈,在知足最小使用代價的前提下,兩套系統工做半徑的平方分別爲180blog

算法分析排序

參考

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

http://hzwer.com/44.html

假設兩個導彈系統爲p一、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[100005];//存儲全部的導彈 
18     int i,j;
19     int r1,r2,cost,minCost=-1;
20     
21     scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
22     scanf("%d",&N);
23     for(i=0;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[0]),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=0;
36     r1=D[0].d1;
37     minCost=r1+r2;
38     
39     r2=D[0].d2;
40     for(i=1;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-1].d2) r2=D[i-1].d2;
44         cost=r1+r2;
45         if(cost<minCost) minCost=cost;
46     }
47     
48     //第二種極限狀況:全部導彈均由p2攔截 
49     r1=0;
50     if(r2<D[N-1].d2) r2=D[N-1].d2;
51     cost=r1+r2;
52     if(cost<minCost) minCost=cost;
53     
54     printf("%d\n",minCost);        
55     return 0;
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[100005];
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=1;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+1,a+n+1,cmp);//對a[1]~a[n]進行排序,按照a[i].s1升序排序 
32     
33     int rb=0;
34     a[n+1].s2=0;
35     for(int i=n;i>0;i--)//從離a最遠的導彈開始枚舉
36     {
37         rb=max(a[i+1].s2,rb);//將i+1號導彈交給系統b,更新系統b的半徑
38         mn=min(mn,a[i].s1+rb);//更新答案
39     }
40     
41     //一種極限狀況 
42     rb=max(a[1].s2,rb);//將全部導彈交給系統b,更新系統b的半徑
43     mn=min(mn,0+rb);//更新答案
44     
45     printf("%d",mn);
46     return 0;
47 }
相關文章
相關標籤/搜索