區間貪心
阿新 • • 發佈:2018-11-02
題目大意:以x軸為分界,y>0部分為海,y<0部分為陸地,給出一些島嶼座標(在海中),再給出雷達可達到範圍,雷達只可以安在陸地上,問最少多少雷達可以覆蓋所以島嶼 本題貪心思路是把點轉化為在x軸座標上的區間(即能保證覆蓋該小島的雷達所有可能位置的集合),然後按點的順序排也行,按左端點排也行。然後最左邊的依次向右遍歷,如果下一個區間的最左端在上一個雷達的右端,顯然需要放一個新雷達;如果在左端的話,則需要判斷最右端了,如果最右端也在上個雷達左端的話,那麼這個雷達顯然不能覆蓋當前這個小島,需要把雷達位置調整為當前區間的最右端,這樣既能覆蓋之前的也能覆蓋現在的;如果最右端在上個雷達右端,則無需調整也無需放置新雷達。 --------------------- 作者:詹明捷 來源:CSDN 原文:https://blog.csdn.net/ACM_10000h/article/details/41009307 版權宣告:本文為博主原創文章,轉載請附上博文連結!
題意:雷達如何放置?在xoy二維平面座標系裡面,x軸上方的為島嶼,x軸下方的是雷達要放到位置,如何放使得雷達放的最少?
思路
- 肯定放在x軸上減少浪費是最好的選擇
- 什麼情況下,雷達無法到達呢?--以這個島嶼為圓心,d為半徑,如果這個圓與x軸沒有交點的話,就是無法覆蓋到---即y>d
- 現在就可以這麼想了,每個島嶼都當成圓心C,然後都取畫圓,跟x軸的交點例如交點A,B.如果雷達放到AB之間那就是可以將剛才C覆蓋住了。--轉為區間貪心問題
區間貪心問題:
- 先將各個區間的左端點按照從小到大排序
- 然後按遞增序列開始選取區間,有兩種情況 例項說明
import java.util.*; public class Main { public static void main(String args[]){ Scanner in=new Scanner(System.in); int cnt_test=0; while(in.hasNext()){ cnt_test++; int n=in.nextInt(); int d=in.nextInt(); if(n==0 && d==0){ break; }else{ int num[][]=new int[n][2]; for(int i=0;i<n;i++){ num[i][0]=in.nextInt(); num[i][1]=in.nextInt(); } //判斷是否存在距離x軸大於d的點,這種點將無法覆蓋 int flag=0; for(int i=0;i<n;i++){ if(Math.abs(num[i][1])>d){ System.out.println("Case "+cnt_test+": -1"); flag=1; break; } } if(flag==0){ //計算每個島嶼在海岸線(x軸上的區間) List listd=new ArrayList<Point1>(); for(int i=0;i<n;i++){ double z=Math.sqrt((d*d-num[i][1]*num[i][1])*1.0); double zuo=num[i][0]*1.0-z; double you=num[i][0]*1.0+z; listd.add(new Point1(zuo,you)); } //區間排序 Collections.sort(listd, new Comparator<Point1>() { public int compare(Point1 p1,Point1 p2){ if(p1.zuo>=p2.zuo){ return 1; }else{ return -1; } } }); //計算最小點數 Point1 t0=(Point1)listd.get(0); double you=t0.you; int cnt=1; for(int i=1;i<n;i++){ Point1 ti=(Point1)listd.get(i); if(ti.zuo>you){ cnt++; you=ti.you; }else if(ti.you<you){ you=ti.you; } } System.out.println("Case "+cnt_test+": "+cnt); } } } } } class Point1{ double zuo; double you; Point1(double zuo,double you){ this.zuo=zuo; this.you=you; } }