题目描述
题目分析
将野人居住地看作顶点,之间的距离看作边,部落看作集合,考虑用最小生成树Kruskal算法解决,同一个部落里的居住点就构成一个连通分量。使用Kruskal算法时,设初始部落数为,每有两个原本不在一个集合的顶点被合并,意味着减少一个部落。当部落数减少为时,下一个最小的待合并边即为本题答案。
我的代码
#include <iostream>
#include <algorithm>
#include <cmath>
#include <map>
using namespace std;
int par[1000000];
pair<int,int> V[1000]; //坐标
multimap<float, int> E;
multimap<float, int>::iterator it;
//并查集初始化
void init(int x) {
for (int i = 0; i < x; i++)
{
par[i] = i;
}
}
//查询
int find(int x) {
if (par[x] == x) {
return par[x];
}
else {
par[x] = find(par[x]);
return par[x];
}
}
//合并
void unite(int x, int y) {
x = find(x);
y = find(y);
par[x] = y;
}
//主函数
int main(void) {
int n;//居住点数量
int k;//部落数量
//输入
cin >> n >> k;
for (int i = 0; i < n; i++)
{
cin >> V[i].first >> V[i].second;
}
//初始化
init(1000000);//并查集初始化
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
float dis = sqrt(pow(abs(V[i].first - V[j].first), 2) + pow(abs(V[i].second - V[j].second),2)); //计算距离
int index = i + j * 1000; //计算序号
E.insert(pair<float, int>(dis, index)); //容器排序
}
}
it = E.begin();
int num = n;
float ans;
while (it != E.end()) {
int x = (*it).second % 1000;
int y = ((*it).second - x) / 1000;
if (find(x) == find(y)) {
}
else if(num != k){
unite(x, y);
num--;
}
else {
ans = (*it).first;
break;
}
it++;
}
printf("%.2f", ans);
return 0;
}