Xiaowo

I Lay My Love On You~

岛国问题

【问题描述】一家互联网服务商(简称PIN)在太平洋上发现了几座新岛屿,其中最大的一个岛(称为主岛)已经连接到Internet,但是其他岛和主岛之间没有光缆连接,所以无法上网。为了让所有岛上的居民都能上网,每个岛和主岛之间都必须有直接或者间接的光缆连接。
       每条实线表示一根光缆,它的长度等于两个岛屿中心位置(路由器位置)的几何距离,图上的数字是该岛上的居民数量。为了节省成本,所有光缆的总长度尽量小。  


       岛屿之间的光缆同时开始铺设,以每天一公里的速度铺设,那么较短的路径肯定先铺设完,某岛屿只要与主岛之间存在一条已经铺设好的电缆,就能接入互联网。PIN非常关注所有居民的平均接入互联网的时间,假设第 i 个岛屿的居民人数是mi ,接入互联网需要的时间是ti ,则平均接入时间是:

 


【输入形式】输入内容包括所有岛屿的信息。第一行是岛屿的个数nn< 50);接下来共有n行,每一行包括三个正整数:xi  yi  mi ,中间空格隔开,(xi , yi )是岛屿的位置坐标,坐标轴单位是公里,mi 是该岛屿的居民人数。输入的第一个岛屿是主岛。
【输出形式】输出所有居民的平均接入互联网的平均天数,结果保留两位小数。
【样例输入】

7
11 12 2500
14 17 1500
9 9 750
7 15 600
19 16 500
8 18 400
15 21 250
【样例输出】3.20
【样例说明】不用考虑岛屿之间具有相同距离的情况
【评分标准】该题目由2002年的ACM/ICP World Final改编而成,作为选做题


分析:

本题可用之前分析的Prim最小生成树来生成路径,之后的关键就是在找到这些边的时候记录下这些边,并算出需要等待的时间。

需要等待的时间——

若岛A直接连接到主岛,则A岛需要等待的时间就是二者的距离

假设A通过B连接到主岛,

如果A到B的边长小于B到主岛的边长,则A岛等的时间实际上是B到主岛的时间

否则如果A到B的边长大于B到主岛的边长,则A岛等的时间是A岛修光缆到B岛的时间

#include<stdio.h>
#include<string.h>
#include<math.h>

#define INF 0xfffffff							// infinity
#define MAXSIZE 20

int n;
int people[MAXSIZE], point[MAXSIZE][2];			//point[]记录点的坐标位置
double edge[MAXSIZE][MAXSIZE], time[MAXSIZE];	//因为每天铺一公里,所以time[]其实就是距离

void Prim(double edge[][MAXSIZE], int u);
double distance(int a, int b, int c, int d);

int main()
{
	int i, j;
	int sum_people = 0;
	double sum_time = 0;

	memset(edge, 0, sizeof(edge));				// void * memset (void * p,int c,size_t n)
	scanf("%d", &n);
	for(i = 1; i <= n; i++)						//读点的坐标和人数
		scanf("%d%d%d", &point[i][0], &point[i][1], &people[i]);

    for(i = 1; i <= n; i++)						//计算总人数
        sum_people += people[i];

	for(i = 1; i <= n; i++)						// 构造邻接矩阵
		for(j = 1; j <= n; j++)
			edge[i][j] = edge[j][i] = distance(point[i][0], point[i][1], point[j][0], point[j][1]);

	Prim(edge, 1);						//Prim算法,从主岛(顶点1)开始

	for(i=2; i<=n; i++)					//计算所有人等待的总时间(主岛除外),故i=2
		sum_time += time[i] * people[i];

	printf("%.2f\n", sum_time / sum_people);
	return 0;
}

void Prim(double edge[][MAXSIZE], int u)
{
	int nearvex[MAXSIZE] = {0};
	double lowcost[MAXSIZE] = {0}, mincost = INF * 1.0;
	int i, j;
	int v = -1;
	double weight = 0;

	for(i=1; i<=n; i++)							//NO.1 对距离进行初始化
	{
		lowcost[i] = edge[u][i];
		nearvex[i] = u;
	}
	lowcost[u] = 0;
	nearvex[u] = -1;

	for(i=1; i<n; i++)					//NO.4 循环n-1次,加入n-1个顶点
	{
        mincost = INF;		// very important!!!!! EVERY TIME mincost should be initialized to find the minimum
		for(j=1; j<=n; j++)				//NO.3 更新距离,找到边的权值最小的那个点
			if(nearvex[j] != -1 && lowcost[j] < mincost)
			{
				mincost = lowcost[j];
				v = j;				//记录下这个边的权值最小的点
			}

		if(v != -1)					//如果找到那个点,进行NO.2
		{
	//		printf("%d--(%f)-->%d\n", nearvex[v], lowcost[v], v);   //打印加入的流程
//****************************************************************************************************************
//相对于最小生成树的关键代码:
			if(nearvex[v] == u)				//若毗邻主岛,直接将时间(距离)更新为边长
				time[v] = lowcost[v];
			else if(lowcost[v] <= time[ nearvex[v] ])
				time[v] = time[ nearvex[v] ];
				else
					time[v] = lowcost[v];
//假设A通过B连接到主岛,如果A到B的边长小于B到主岛的边长,则A岛等的时间实际上是B到主岛的时间
//否则如果A到B的边长大于B到主岛的边长,则A岛等的时间是A岛修光缆到B岛的时间
//****************************************************************************************************************

			nearvex[v] = -1;					//将点加入T2
			weight += lowcost[v];

			for(j=1; j<=n; j++)					//加入后,对距离进行更新
			{
				if(nearvex[j] != -1 && edge[v][j] < lowcost[j])
				{
					lowcost[j] = edge[v][j];
					nearvex[j] = v;
				}
			}
		}
	}
}

double distance(int a, int b, int c, int d)
{
	return sqrt( (a-c)*(a-c) + (b-d)*(b-d) );
}


阅读更多
版权声明:本文为博主原创文章,欢迎转载欢迎传播,注不注明出处随你,只要对更多人有所帮助就行。 https://blog.csdn.net/puppylpg/article/details/41695677
文章标签: MST
个人分类: C/C++编程题目
上一篇从下至上按层遍历由广义表(节点为数字)构造的二叉树
下一篇最优配餐 广度优先搜索
想对作者说点什么? 我来说一句

64k高压缩3D动画影片-光影

2011年11月05日 40KB 下载

JAVA实现磁力链接搜索

2016年11月26日 266KB 下载

win7的上帝模式使用

2012年01月11日 15KB 下载

AndroidUm.apk

2017年12月26日 1.31MB 下载

指派问题,解决原理及示例代码

2012年05月09日 286KB 下载

C++吃水果问题

2011年11月26日 4KB 下载

指派问题matlab代码

2015年04月08日 621B 下载

用回溯法求解跳马问题

2007年07月13日 1.7MB 下载

指派问题 匈牙利算法实现

2009年06月04日 5KB 下载

没有更多推荐了,返回首页

关闭
关闭