洛谷 P1991 无线通信网

题目链接:无线通讯网 - 洛谷

题目描述

国防部计划用无线网络连接若干个边防哨所。2 种不同的通讯技术用来搭建无线网络;

每个边防哨所都要配备无线电收发器;有一些哨所还可以增配卫星电话。

任意两个配备了一条卫星电话线路的哨所(两边都ᤕ有卫星电话)均可以通话,无论他们相距多远。而只通过无线电收发器通话的哨所之间的距离不能超过 DD,这是受收发器的功率限制。收发器的功率越高,通话距离 DD 会更远,但同时价格也会更贵。

收发器需要统一购买和安装,所以全部哨所只能选择安装一种型号的收发器。换句话说,每一对哨所之间的通话距离都是同一个 DD。你的任务是确定收发器必须的最小通话距离 DD,使得每一对哨所之间至少有一条通话路径(直接的或者间接的)。

输入格式

从 wireless.in 中输入数据第 1 行,2 个整数 SS 和 PP,SS 表示可安装的卫星电话的哨所数,PP 表示边防哨所的数量。接下里 PP 行,每行两个整数 x,yx,y 描述一个哨所的平面坐标 (x,y)(x,y),以 km 为单位。

输出格式

输出 wireless.out 中

第 1 行,1 个实数 DD,表示无线电收发器的最小传输距离,精确到小数点后两位。

输入输出样例

输入 #1

2 4
0 100
0 300
0 600
150 750

输出 #1

212.13

说明/提示

对于 20%20% 的数据:P=2,S=1P=2,S=1

对于另外 20%20% 的数据:P=4,S=2P=4,S=2

对于 100%100% 的数据保证:1≤S≤1001≤S≤100,S<P≤500S<P≤500,0≤x,y≤100000≤x,y≤10000。

 算法:最小生成树

思路:

与道路建设那个题类似,就是在那个的代码基础上加了一个排序
先不管是否装电话,
将所有哨所用无向图最小生成树连接起来,
将无向图中所有边(dist数组)从大到小排序
dist[s]即是最后答案

代码:

#include<stdio.h>
#include<string.h>
#include<math.h>
#define size 10001
double dist[size];//起点到其余各顶点的最短路径长度,初始化为无穷大
bool book[size];//用来标记顶点是否已经并入最短路径,初始化为false表示没有被纳入最短路径
int s, p;//分别表示点的个数,哨所的个数
double all; //all存树路径之和
double map[size][size];//map[i][k]表示从i到k的距离
void init() { //算法初始化
	memset(book, 0, sizeof(book));
	memset(dist, 0x7f, sizeof(dist));
	all = 0; //路径之和清0
	book[1] = true; //1为默认源点,源点进入最小生成树
}
void run_prim() {
	for (int h = 1; h < p; h++) { //最小生成树中共进入n个顶点,当前生成树中顶点个数为h
		int k = 0;
		for (int i = 1; i <= p; i++) { //从没有进入树的点中找到离树的任意一个顶点最近的一个点
			if (!book[i] && dist[i] < dist[k]) {
				k = i;
			}
		}
		all += dist[k];
		book[k] = true; //标记该点已经进入最短生成树
		for (int i = 1; i <= p; i ++) { //扫描k点所有的边,再以k点为中转点,更新生成树到每一个非树顶点的距离
			if (!book[i] && dist[i] > map[i][k] ) {
				dist[i] = map[i][k];
			}
		}
	}
}
double cal_dist(int x1, int y1, int x2, int y2) {
	return sqrt((double)(x1 - x2) * (x1 - x2) + (double)(y1 - y2) * (y1 - y2));
}
int xy[size][2];//存坐标点坐标
void InsertSort(double* a, int n) {
	for (int i = 0; i < n - 1; i++) {
		int end = i;
		double tmp = a[end + 1];
		while (end >= 0) {
			if (tmp > a[end]) {
				a[end + 1] = a[end];
				end--;
			} else {
				break;
			}
		}
		a[end + 1] = tmp;
	}
}
int main() {
	scanf("%d %d", &s, &p );
	init();//输入n,m,s之后再初始化
	for (int i = 1; i <= p; i++) { //输入坐标
		scanf("%d %d", &xy[i][0], &xy[i][1]);
	}
	for (int i = 1; i <= p; i++) {
		for (int k = 1; k <= p; k++) {
			double tt = cal_dist(xy[i][0], xy[i][1], xy[k][0], xy[k][1]);
			map[i][k] = tt;
			map[k][i] = tt;
		}
	}
	for (int i = 1; i <= p; i++) {
		dist[i] = map[1][i];
	}
	run_prim();
	dist[0] = 0;
	InsertSort(dist, p + 1);//插入排序
	/*
	for(int i=0;i<=p;i++){
		printf("%.2lf\n",dist[i]);
	}	
	*/
	printf("%.2lf", dist[s - 1]);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值