1821. [JSOI2010]部落劃分【並查集+二分】
阿新 • • 發佈:2018-04-01
pac post put 可能 rip esp 標註 urn das
0 0
0 1
1 1
1 0
Description
聰聰研究發現,荒島野人總是過著群居的生活,但是,並不是整個荒島上的所有野人都屬於同一個部落,野人們總是拉幫結派形成屬於自己的部落,不同的部落之間則經常發生爭鬥。只是,這一切都成為謎團了——聰聰根本就不知道部落究竟是如何分布的。 不過好消息是,聰聰得到了一份荒島的地圖。地圖上標註了N個野人居住的地點(可以看作是平面上的坐標)。我們知道,同一個部落的野人總是生活在附近。我們把兩個部落的距離,定義為部落中距離最近的那兩個居住點的距離。聰聰還獲得了一個有意義的信息——這些野人總共被分為了K個部落!這真是個好消息。聰聰希望從這些信息裏挖掘出所有部落的詳細信息。他正在嘗試這樣一種算法: 對於任意一種部落劃分的方法,都能夠求出兩個部落之間的距離,聰聰希望求出一種部落劃分的方法,使靠得最近的兩個部落盡可能遠離。 例如,下面的左圖表示了一個好的劃分,而右圖則不是。請你編程幫助聰聰解決這個難題。
Input
第一行包含兩個整數N和K(1< = N < = 1000,1< K < = N),分別代表了野人居住點的數量和部落的數量。 接下來N行,每行包含兩個正整數x,y,描述了一個居住點的坐標(0 < =x, y < =10000)Output
輸出一行,為最優劃分時,最近的兩個部落的距離,精確到小數點後兩位。
Sample Input
4 20 0
0 1
1 1
1 0
Sample Output
1.00
這不就是個傻(bi-----)題嗎OvO
感覺我這語文怕是藥丸,讀了半天才明白題意
設距離為x,那麽兩個居住地之間的距離若小於x,那麽這兩個居住地就屬於同一部落 畢竟部落間的間隔不全相同,很難得出一個確定的答案
那麽我們就確定答案然後再判定
又因為答案滿足單調性,所以我們可以二分判定答案
再看並查集是由幾個樹構成的
若ans滿足有大於等於k個樹就縮小ans
否則擴大
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cmath> 5 using namespace std; 6 struct node 7 { 8 int x,y; 9 }a[1001]; 10 int Father[1001],n,k; 11 12 double Dis(int x,int y) 13 { 14 return (sqrt((a[x].x-a[y].x)*(a[x].x-a[y].x)+(a[x].y-a[y].y)*(a[x].y-a[y].y))); 15 } 16 17 int Find(int x) 18 { 19 if (x==Father[x]) return Father[x]; 20 Father[x]=Find(Father[x]); 21 return Father[x]; 22 } 23 24 void Merge(int x,int y) 25 { 26 int fx=Find(x); 27 int fy=Find(y); 28 Father[fx]=fy; 29 } 30 31 bool check(double len) 32 { 33 for (int i=1;i<=n;++i) 34 Father[i]=i; 35 for (int i=1;i<=n-1;++i) 36 for (int j=i+1;j<=n;++j) 37 if (i!=j && Dis(i,j)<=len && Find(i)!=Find(j)) 38 Merge(i,j); 39 int cnt=0; 40 for (int i=1;i<=n;++i) 41 if (Father[i]==i) 42 ++cnt; 43 if (cnt<k) 44 return false; 45 else 46 return true; 47 } 48 49 int main() 50 { 51 scanf("%d%d",&n,&k); 52 for (int i=1;i<=n;++i) 53 scanf("%d%d",&a[i].x,&a[i].y); 54 55 double l=0,r=10000; 56 while (r-l>=0.0001) 57 { 58 double mid=(l+r)/2; 59 if (check(mid)) 60 l=mid; 61 else 62 r=mid; 63 } 64 printf("%0.2lf",l); 65 }
1821. [JSOI2010]部落劃分【並查集+二分】