通過11 年的韜光養晦,某國研發出了一種新的導彈攔截系統,凡是與它的距離不超過其工做半徑的導彈都可以被它成功攔截。當工做半徑爲0 時,則可以攔截與它位置剛好相同的導彈。但該導彈攔截系統也存在這樣的缺陷:每套系統天天只能設定一次工做半徑。而當天的使用代價,就是全部系統工做半徑的平方和。
某天,雷達捕捉到敵國的導彈來襲。因爲該系統尚處於試驗階段,因此只有兩套系統投入工做。若是如今的要求是攔截全部的導彈,請計算這一天的最小使用代價。html
數據範圍
對於10%的數據,N = 1
對於20%的數據,1 ≤ N ≤ 2
對於40%的數據,1 ≤ N ≤ 100
對於70%的數據,1 ≤ N ≤ 1000
對於100%的數據,1 ≤ N ≤ 100000,且全部座標份量的絕對值都不超過1000。
ios
第一行包含4 個整數x一、y一、x二、y2,每兩個整數之間用一個空格隔開,表示這兩套導彈攔截系統的座標分別爲(x1, y1)、(x2, y2)。
第二行包含1 個整數N,表示有N 顆導彈。接下來N 行,每行兩個整數x、y,中間用一個空格隔開,表示一顆導彈的座標(x, y)。不一樣導彈的座標可能相同。算法
輸出只有一行,包含一個整數,即當天的最小使用代價。函數
0 0 10 0
2
-3 3
10 0spa
18.net
兩個點(x1, y1)、(x2, y2)之間距離的平方是(x1− x2)^2+(y1−y2)^2。
兩套系統工做半徑r一、r2 的平方和,是指r一、r2 分別取平方後再求和,即r1^2+r2^2。code
【樣例說明】htm
樣例1中要攔截全部導彈,在知足最小使用代價的前提下,兩套系統工做半徑的平方分別爲18和0。blog
算法分析排序
參考
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 }