【最小生成树-第k大边】Arctic Network POJ - 2349
Arctic Network POJ - 2349
相似题目:POJ 2253 Frogger
题意:
给定\(p\)个哨所的坐标,可任意使其中\(s\)个拥有卫星通讯功能。任意两个具有卫星通讯功能的哨所视为连通。在剩下的哨所之间建立无线电路径,路径的花费\(D\)为哨所之间的距离。求能使所有哨所连通的最小的\(D\)。
思路:
如果忽略卫星通讯这个条件,题目所求的明显是最小生成树的最大边。
加上卫星通讯这个条件,就相当于可以使最小生成树中的任意\(s-1\)条边免费,再在剩下不免费的边中找出花费最大的那一条。
结合题意,将最小生成树的所有边从大到小排序,使前\(s-1\)条边免费,那么第\(s\)条边的花费就是答案了。
差点就1A了,但是因为把500*500算成了25000导致数组开小了而RE了一发……
int fa[maxn];
int tmp1[maxn], tmp2[maxn];
int u[maxn], v[maxn];
double w[maxn];
double edge[maxn];
int n, m, m2, k;
struct node {
double x, y;
}N[maxn];
int find(int x) {
return fa[x] == x ? x : fa[x] = find(fa[x]);
}
bool cmp1(int i, int j) {
return w[i] < w[j];
}
bool cmp2(int i, int j) {
return edge[i] > edge[j];
}
double count(node t1, node t2) {
double dx = t1.x - t2.x;
double dy = t1.y - t2.y;
return sqrt(dx * dx + dy * dy);
}
double solve() {
// double ans = 0;
for (int i = 0; i < maxn; i++) fa[i] = i;
for (int i = 0; i < m; i++) tmp1[i] = i;
for (int i = 0; i < m; i++) tmp2[i] = i;
sort(tmp1, tmp1 + m, cmp1);
//板子内容,将备选的所有边从小到大排序,以便计算最小生成树
for (int i = 0; i < m; i++) {
int e = tmp1[i];
int from = find(u[e]);
int to = find(v[e]);
if (from != to) {
// ans += w[e];
edge[m2++] = w[e];
//记录最小生成树中边的花费
fa[from] = to;
}
}
sort(tmp2, tmp2 + m2, cmp2);
//将最小生成树中的所有边从大到小排序,只将结果以下标形式保存在tmp2中
return edge[tmp2[k-1]];
//注意tmp2下标从0开始,第x大的边下标为x-1
//题目给定的卫星信道不是边,是拥有该功能的点的数量
//k个卫星信道形成k-1条边,所以要求的是树中第k大条边
// return ans;
}
int main()
{
//ios::sync_with_stdio(false);
int t; cin >> t; while (t--) {
m = 0;
m2 = 0;
cin >> k >> n;
for (int i = 1; i <= n; i++) {
cin >> N[i].x >> N[i].y;
for (int j = i-1 ; j >= 1; j--) {
double tp = count(N[i], N[j]);
u[m] = i; v[m] = j; w[m] = tp; m++;
u[m] = j; v[m] = i; w[m] = tp; m++;
}
}
printf("%.2f\n", solve());
}
return 0;
}