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;
}
posted @ 2018-07-27 00:05  Garen-Wang  阅读(217)  评论(0编辑  收藏  举报