luogu P1991 无线通讯网

原题链接:https://www.luogu.org/problem/show?pid=1991

 

首先此题给出的边并不是常规的形式,而是坐标式,所以要枚举所有的点的情况,求出所有的边的边长。

很显然,用最小生成树能够求出所有点联通时的最长边的距离,但是因为有无线电收发器的情况,所以可以免去一些边的选用。

之后考虑配备无线电收发器的情况,假设我们已经有了最小生成树,如果只有一个收发器,那么相当于没有,它自己是派不上用场的。

如果有两个收发器,很显然,应该装在最长的边的两个端点处,这样就可以减少一条最长的边。

第三台怎么办呢?找到一个最长的边,任意选它的一个端点,将它与现有的有收发器的点之间再连一条边,将这条边的长度记为0,于是这条边也可以忽略不计了。第四台,第五台以此类推。。。

这样就能发现,一共需要在原最小生成树上选最短的n-s条边(s为无线电收发器的个数)。

最后说一点优化,为了防止精度问题,同时又因为边权比较小,所有可以存储边的距离的平方,将最后结果开方输出便可。

 

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
void read(int &y)
{
    y=0;char x=getchar();
    while(x<'0'||x>'9') x=getchar();
    while(x>='0'&&x<='9')
    {
        y=y*10+x-'0';
        x=getchar();
    }
}
int x[505],y[505],f[505],cnt;
struct edge
{
    int u,v,w;
}e[150005];
int find(int x)
{
    if(f[x]==x) return x;
    return f[x]=find(f[x]);
}
bool cmp(edge a,edge b)
{
    return (a.w<=b.w);
}
int main()
{
    int s,p;
    read(s);read(p);
    int t=p-s;
    for(int i=1;i<=p;i++)
    {
        read(x[i]);read(y[i]);
        f[i]=i;
    }
    for(int i=1;i<=p;i++)
    {
        for(int j=i+1;j<=p;j++)
        {
            e[++cnt].w=(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]);
            e[cnt].u=i;
            e[cnt].v=j;
        }
    }
    sort(e+1,e+cnt+1,cmp);
    for(int i=1;i<=cnt;i++)
    {
        int a=find(e[i].v),b=find(e[i].u); 
        if(a==b) continue;
        f[find(b)]=a;
        t--;
        if(t==0)
        {
            double ans=sqrt(e[i].w);
            printf("%.2lf",ans);
            return 0;
        }
    }
    return 0;
}

 

posted @ 2017-09-28 20:42  Excim  阅读(276)  评论(0编辑  收藏  举报