题目链接
https://cn.vjudge.net/contest/245639#problem/D
题目大意
将n个顶点连接起来, 使得边的权值之和最小, 而题目要输出的不是最小权值和, 而是在最小生成树上找出一条权值最大
的边, 输出这条边的权值 ,当然是有前提的, 要先除去s-1条最大的边, 因为这s-1条边是无限制连接的.
题目分析
采用kruskal法将选中的n-1条边存入一个数组sum中, 输出sum[n-1-s]即可, 现在来分析n-s-1怎么得来的
根据树的性质: 一共有n个顶点, 所以树有n-1条边, 有s个卫星传输, 可使得s-1条边不限制传输, 所以还剩下n-1-(s-1)条边,
我们要的就是这第 n-1-(s-1) 条边的权值
而sum[0]是第1条边, sum[1]是第2条边, 所以第n-1-(s-1)条边就是sum[n-1-(s-1)-1] , 即sum[n-1-s].
一开始写了好多遍都没过, 一直WA, 也找不出哪里有问题, 修修改改还是WA, 最后干脆把代码全部删掉重新写了一遍就直接AC了.
代码示例
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
const int maxn = 200000 + 5;
int per[maxn],n,m,s;
double sum[maxn];
struct node{ int from, to; double val; }e[maxn];
struct vet{ double x, y; }v[maxn];
int find(int x){ return per[x] == x ? x : per[x] = find(per[x]); }
bool cmp(node a, node b){ return a.val < b.val; }
void init()
{
for (int i = 1; i <= n; i++) per[i] = i;
}
void input()
{
for (int i = 1; i <= n; i++)
cin >> v[i].x >> v[i].y;
m = 0;
for (int i = 1; i < n;i++)
for (int j = i + 1; j <= n; j++)
{
e[m].from = i;
e[m].to = j;
e[m++].val = sqrt((v[i].x - v[j].x)*(v[i].x - v[j].x) + (v[i].y - v[j].y)*(v[i].y - v[j].y));
}
sort(e, e + m, cmp);
//for (int i = 0; i < m; i++)
// printf("%d %d %lf\n", e[i].from, e[i].to, e[i].val);
}
void kruskal()
{
int num = 0;
for (int i = 0; i < m; i++)
{
int fa = find(e[i].from), fb = find(e[i].to);
if (fa != fb)
{
per[fa] = fb;
sum[num++] = e[i].val;
}
}
printf("%.2lf\n", sum[n - s - 1]);
}
int main()
{
int t; cin >> t;
while (t--)
{
cin >> s >> n;
init();
input();
kruskal();
}
return 0;
}