题解 P1991 【无线通讯网】

题目

这一题对我有历史性的意义,因为我深刻意识到:

不要用namespace!

不要用namespace!

不要用namespace!

写此题解,以示他人。

(搞错重点了吧喂!)


好,回归正题:

这道题的思路是这样:

首先,用Kruskal算法。

(建议先把 并查集模板与 最小生成树模板 打了再继续看)

我们回顾一下Kruskal算法的过程:

把边按权值从小到大一条条排好,然后再从未选择的点中添加边,一直添加到节点数-1为止。

重点:为什么是节点数-1?因为最小生成树要让图连通。

可不可以不连通?

可以!

该题中,卫星电话的存在,就是为了可以让图断开。而最后求的最大边,就是最后一个添加到图中的边。

附上代码:

#include <bits/stdc++.h>
#define MAXN 200005
int node,edgenum=0,ans=0,k=0,s;
int fat[MAXN],siz[MAXN];
//坐标 
struct pair
{
	int first,second;
}	a[MAXN];
//图 
struct EDGE
{
	int from,to;double cost;
}	e[MAXN];
//比较器 
bool cmp(EDGE a,EDGE b)	{return a.cost<b.cost;}
//并查集 + 路径压缩 + 启发式搜索 
int Find(int x){ return (fat[x]==x)? x : fat[x]=Find(fat[x]); }
void unionn(int x,int y){
	x=Find(x); y=Find(y);
	if(siz[x]>siz[y])	std::swap(x,y);
	fat[x]=y;	siz[y]+=siz[x]; 
}
//两点之间距离公式 
double distance(pair m , pair n)
{
	double ans=std::sqrt( (m.first-n.first)*(m.first-n.first) + (m.second-n.second)*(m.second-n.second) );
	return ans;
}

int main()
{
	double d;
	std::scanf("%d%d",&s,&node);
	for(int i=1;i<=node;++i)	scanf("%d%d",&a[i].first,&a[i].second);
	for(int i=1;i<=node;++i)	{fat[i]=i;	siz[i]=1;}	//初始化 
	for(int i=1;i<=node;++i)	//构图 
	{
		for(int j=i+1;j<=node;++j)
		{
			e[ ++edgenum ].from=i;	e[ edgenum ].to=j;
			e[ edgenum ].cost=distance(a[i],a[j]);
		}
	}
	//	Kurskal 
	std::sort(e+1,e+edgenum+1,cmp);
	for(int i=1;i<=edgenum;++i)
	{
		if(k==node-s) break;//节点数-卫星电话数
		if(Find(e[i].from) != Find(e[i].to))
		{
			unionn(e[i].from,e[i].to); 
			d=e[i].cost;	++k; 
		}
	}		
	std::printf("%.2lf",d);
	return 0;
}

其实这题的数据有点弱。

我的代码是有缺陷的,可是AC了。

应该还要再添加一些特判。

比如,当卫星电话数大于节点数时,d应该为0。

当卫星电话数为0时,应该与卫星电话为1时的情况相等。

posted @ 2020-07-27 00:22  x_miracle  阅读(101)  评论(0编辑  收藏  举报