P1991 无线通讯网
语文神题。。。
翻题解才大概知道意思,题目就是不给你说清题意。
大意
现在给你\(p\)个点,其中与\(s\)个点相连无需费用。
然后要你连接起所有的点,求最优方案中需要的最大费用。
连接这\(p\)个点,当然是使用生成树\(p - 1\)条边优。
更具体的是使用最小生成树,这样一定最优。
\(s\)个点相连无需费用,说白了就是\(s - 1\)条边相连无需费用。
那么做生成树要\(p - 1\)条边,可以免掉的边肯定是最小生成树中费用最多的那些边了。
挑掉那些免费化的边后,就是答案了。
这里实现的时候有个坑:在排序后的边中,你添加边当然不是连续的,可能会有间隔。所以不能直接在原边中减出下标来。
解决方法是记下每一条添加进去的边,再减出下标,取出来就ok了。
代码:
#include<cstdio>
#include<cmath>
#include<algorithm>
const int maxn = 505;
struct Edges
{
int u, v;
double w;
} e[maxn * maxn], ee[maxn];
int pos;
int tot;
int x[maxn], y[maxn];
int fa[maxn];
double ans;
int s, p;
int read()
{
int ans = 0, s = 1;
char ch =getchar();
while(ch > '9' || ch < '0')
{
if(ch == '-') s = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
ans = ans * 10 + ch - '0';
ch = getchar();
}
return s * ans;
}
double dist(int i, int j)
{
return sqrt((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]));
}
int find(int x)
{
if(fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
bool cmp(const Edges a, const Edges b)
{
return a.w < b.w;
}
void merge(int x, int y)
{
x = find(x), y = find(y);
if(x != y) fa[x] = y;
}
int main()
{
s = read(), p = read();
for(int i = 1; i <= p; i++)
{
x[i] = read(), y[i] = read();
fa[i] = i;
}
for(int i = 1; i <= p; i++)
{
for(int j = i + 1; j <= p; j++)
{
e[++tot] = (Edges){i, j, dist(i, j)};
}
}
std::sort(e + 1, e + tot + 1, cmp);
for(int i = 1; i <= tot; i++)
{
int u = e[i].u, v = e[i].v;
if(find(u) != find(v))
{
merge(u, v);
ee[++pos] = e[i];
}
}
printf("%.2lf\n", ee[pos - s + 1].w);
return 0;
}