BZOJ 1821 Group 部落划分 并查集
题目链接:
https://www.lydsy.com/JudgeOnline/problem.php?id=1821
题目大意:
聪聪研究发现,荒岛野人总是过着群居的生活,但是,并不是整个荒岛上的所有野人都属于同一个部落,野人们总是拉帮结派形成属于自己的部落,不同的部落之间则经常发生争斗。只是,这一切都成为谜团了——聪聪根本就不知道部落究竟是如何分布的。 不过好消息是,聪聪得到了一份荒岛的地图。地图上标注了N个野人居住的地点(可以看作是平面上的坐标)。我们知道,同一个部落的野人总是生活在附近。我们把两个部落的距离,定义为部落中距离最近的那两个居住点的距离。聪聪还获得了一个有意义的信息——这些野人总共被分为了K个部落!这真是个好消息。聪聪希望从这些信息里挖掘出所有部落的详细信息。他正在尝试这样一种算法: 对于任意一种部落划分的方法,都能够求出两个部落之间的距离,聪聪希望求出一种部落划分的方法,使靠得最近的两个部落尽可能远离。 例如,下面的左图表示了一个好的划分,而右图则不是。请你编程帮助聪聪解决这个难题。
思路:
按边排序,从小到大合并,直到恰好连通块数目为k是的边就是最大的最小距离。
1 #include<bits/stdc++.h> 2 #define IOS ios::sync_with_stdio(false);//不可再使用scanf printf 3 #define Max(a, b) ((a) > (b) ? (a) : (b))//禁用于函数,会超时 4 #define Min(a, b) ((a) < (b) ? (a) : (b)) 5 #define Mem(a) memset(a, 0, sizeof(a)) 6 #define Dis(x, y, x1, y1) ((x - x1) * (x - x1) + (y - y1) * (y - y1)) 7 #define MID(l, r) ((l) + ((r) - (l)) / 2) 8 #define lson ((o)<<1) 9 #define rson ((o)<<1|1) 10 #define Accepted 0 11 #pragma comment(linker, "/STACK:102400000,102400000")//栈外挂 12 using namespace std; 13 inline int read() 14 { 15 int x=0,f=1;char ch=getchar(); 16 while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} 17 while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 18 return x*f; 19 } 20 typedef long long ll; 21 const int maxn = 1000 + 10; 22 const int MOD = 1000000007;//const引用更快,宏定义也更快 23 const int INF = 1e9 + 7; 24 const double eps = 1e-6; 25 26 struct node 27 { 28 ll x, y; 29 node(){} 30 node(ll x, ll y):x(x), y(y){} 31 }a[maxn]; 32 struct edge 33 { 34 int u, v; 35 ll w; 36 edge(){} 37 edge(int u, int v, ll w):u(u), v(v), w(w){} 38 bool operator < (const edge& a)const 39 { 40 return w < a.w; 41 } 42 }; 43 vector<edge>e; 44 ll F(int i, int j) 45 { 46 return (a[i].x - a[j].x) * (a[i].x - a[j].x) + (a[i].y - a[j].y) * (a[i].y - a[j].y); 47 } 48 int pa[maxn]; 49 int Find(int x) 50 { 51 return x == pa[x] ? x : pa[x] = Find(pa[x]); 52 } 53 int main() 54 { 55 int n, k; 56 scanf("%d%d", &n, &k); 57 for(int i = 1; i <= n; i++)scanf("%lld%lld", &a[i].x, &a[i].y); 58 for(int i = 1; i <= n; i++) 59 for(int j = i + 1; j <= n; j++) 60 e.push_back(edge(i, j, F(i, j))); 61 sort(e.begin(), e.end()); 62 for(int i = 1; i <= n; i++)pa[i] = i; 63 for(int i = 0; i < e.size(); i++) 64 { 65 if(Find(e[i].u) != Find(e[i].v)) 66 { 67 if(n > k) 68 { 69 n--;//连通块数目减一 70 pa[Find(e[i].u)] = Find(e[i].v); 71 } 72 else 73 { 74 printf("%.2lf\n", sqrt(1.0 * e[i].w)); 75 break; 76 } 77 } 78 } 79 return Accepted; 80 }
越努力,越幸运