无线通讯网(双倍经验)

无线通讯网

洛谷P1991 无线通讯网

前言

这是一道明显的图论题,主要有两种做法:

最小生成树(Kruskal/Prim)、二分&并查集

本篇题解使用第一种做法解决,如果有不懂最小生成树的可以自己先学习一下(能做到这题应该会

最小生成树的学习记录写完后,会挂在这里,欢迎各位来踩qwq


引入

PS:题意直接点击链接即可,还是很简明易懂的,就不多赘述

读完题没有思路,那就对样例下手吧,见图(几何画板真是个好东西啊)

再将这些距离从小到大排个序(因为要求最短距离嘛):

200 < 212.13 < 300 < 474.34 < 500 < 667.08

很明显,要使问题中的无线电收发器的传输距离最小,那么667.08这个距离肯定要避免:所以两个超级电话就安在A、D点,剩下B、C两点,而答案很明显就是212.13

思路推导

  • 将样例转换为一般性问题讨论:

因为题目已经说明任意两点只要直接或间接连接即可,所以我们不需要p条边构造完全图,而只需要p-1条边构造为一棵树

上面s个超级电话之间肯定有(s-1)条边,所以我们还只剩下(p-1-(s-1))=(p-s)条边需要构造

  • 转换样例推导出思路:

我们就可以直接构造最小生成树了呀!构造的最小生成树包含(p-s)条边,剩下的(s-1)条边直接留给超级电话即可


代码Code

明确了思路,这题的代码也就是小问题了,建议大家可以先自己编写啊

现在给出AC代码(使用Kruskal求解最小生成树):

#include <bits/stdc++.h>
using namespace std;
double ans;
int s,p,sx,sy,tot,now,x[2010],y[2010],fa[2010];

struct node {
	int u,v;
	double w;
} e[2010];

inline bool cmp(node xx,node yy) {
	return xx.w<yy.w;
}

inline int find(int x) {
	if(fa[x]==x) return x;
	return fa[x]=find(fa[x]);
}

int main() {
	scanf("%d%d",&s,&p);
	for(register int i=1;i<=p;i++) {
		fa[i]=i;
		scanf("%d%d",&x[i],&y[i]);
		for(register int j=1;j<i;j++) {  //计算每两个点之间的距离(也可以单独开两层循环处理) 
			e[++tot].u=i;
			e[tot].v=j;
			e[tot].w=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
		}
	}
	sort(e+1,e+1+tot,cmp);   //Kruskal求解最小生成树 
	for(register int i=1;i<=tot;i++) {
		int a=find(e[i].u);
		int b=find(e[i].v);
		if(a!=b) {
			fa[a]=b;
			ans=e[i].w;  //因为已经排过序,所以直接更新即可 
			now++;
		}
		if(now==p-s) break;  //如分析,最小生成树只包含p-s条边,剩余的s-1条边使用超级电话解决 
	}
	printf("%.2lf",ans);  //题目要求,保留两位小数输出 
	return 0;
} 

双倍经验

洛谷P4047 [JSOI2010]部落划分

这道题只有判断最小生成树构造完成的判断与无线通讯网不同

简单描述一下思路:给定k个部落,相当于可以少连 \(k-1\) 条边,和卫星电话是差不多的

但是在查找答案时,应该多判断一条边,因为要求是不同部落间的最短距离最大

所以判断改为:if(now==n-k+1) break;


posted @ 2020-06-25 19:39  Eleven谦  阅读(184)  评论(0编辑  收藏  举报