[JSOI2010]部落划分

嘟嘟嘟

一道不错的题,解法不少。

最易于理解的是最小生成树的做法:

首先每两个点之间都连一条长度为这两个点的距离的边,形成完全图。

然后跑最小生成树,直到剩k个联通块,这时候合并成k - 1个联通块的边的长度就是答案(注意,是连接两个联通块的边,否则就不是部落间的距离了)。

正确性很显然。因为这保证了部落内的距离尽量小,则部落外的距离尽量大,所以靠的最近的两个部落也就尽可能的远离。

还有一种二分答案的方法:

每一次把距离小于mid的点都划分成一个部落,最后看形成的部落总数和k的关系,如果小于k,向左二分;否则向右二分。

时间复杂度都是O(ElogE),E为边数,等于n * (n - 1) / 2。(最小生成树算法排序时间O(ElogE),跑kruskal时时O(E)的)

方法一的代码

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<cstring>
 6 #include<cstdlib>
 7 #include<cctype>
 8 #include<vector>
 9 #include<stack>
10 #include<queue>
11 using namespace std;
12 #define enter puts("") 
13 #define space putchar(' ')
14 #define Mem(a, x) memset(a, x, sizeof(a))
15 #define rg register
16 typedef long long ll;
17 typedef double db;
18 const int INF = 0x3f3f3f3f;
19 const db eps = 1e-8;
20 const int maxn = 1e3 + 5;
21 const int maxe = 5e5 + 5;
22 inline ll read()
23 {
24     ll ans = 0;
25     char ch = getchar(), last = ' ';
26     while(!isdigit(ch)) {last = ch; ch = getchar();}
27     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
28     if(last == '-') ans = -ans;
29     return ans;
30 }
31 inline void write(ll x)
32 {
33     if(x < 0) x = -x, putchar('-');
34     if(x >= 10) write(x / 10);
35     putchar(x % 10 + '0');
36 }
37 
38 int n, k;
39 struct Node
40 {
41     int x, y;
42 }a[maxn];
43 struct Edge
44 {
45     int x, y; ll c;
46     bool operator < (const Edge &oth)const
47     {
48         return c < oth.c;
49     }
50 }e[maxe];
51 int ecnt = 0;
52 
53 ll calc(Node a, Node b)
54 {
55     return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
56 }
57 
58 int p[maxn];
59 void init()
60 {
61     for(int i = 1; i <= n; ++i) p[i] = i;
62 }
63 int Find(int x)
64 {
65     return x == p[x] ? x : p[x] = Find(p[x]);
66 }
67 
68 int main()
69 {
70     n = read(); k = read(); 
71     init();
72     for(int i = 1; i <= n; ++i) a[i].x = read(), a[i].y = read();
73     for(int i = 1; i < n; ++i)
74         for(int j = i + 1; j <= n; ++j)
75             e[++ecnt] = (Edge){i, j, calc(a[i], a[j])};
76     sort(e + 1, e + ecnt + 1);
77     int cnt = n;
78     for(int i = 1; i <= ecnt; ++i)
79     {
80         int px = Find(e[i].x), py = Find(e[i].y);
81         if(px != py)
82         {
83             if(cnt-- == k) {printf("%.2lf\n", sqrt(e[i].c)); return 0;}
84             p[px] = py;
85         }
86     }
87     return 0;
88 }
View Code

猜你喜欢

转载自www.cnblogs.com/mrclr/p/9839791.html
今日推荐