uva10369 - Arctic Network

点击http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=116&page=show_problem&problem=1310

题目很简单,直接用krusakl算法即可,然后找出第S大的数,S即为卫星的个数。开始的时候我将卫星之间可以直接通信这一条给忽略了,wrong了N久。后来才注意到这一点。如果最小距离D已知的话,把所有铺设线路的村庄链接起来,构成图后,需要卫星设备的数目就是图的连通支的个数。由这一点出发,我们可以考虑在每个连通支中放置一个卫星,同时使得卫星与卫星之间的距离是最大的,这样就保证了D的值最小,显然我们将生成树中最长的S-1条边去掉之后会形成S个连通分支,这样就得到答案,及求解第S最长边。有关的证明,这里就不在写了,证明得考虑两个问题,1是为什么D不可能比第S长边小,2.生成树有多个的情况下如何保证第S长边是相同的。第二点利用的是最小生成树的边经排序,得到的序列是相同的。程序如下:

/*
ID: csuchenan
PROG: uva10369 - Arctic Network
LANG: C++
*/

#include<iostream>
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
using namespace std ;

struct Point
{
	int x ;
	int y ;
}point[505] ;

struct Edge
{
	int x ;
	int y ;
	double dist ;
}edge[130000] , key[505] ;

int parent[505] ;

double dist_point(Point x , Point y)
{
	return sqrt((double) ( (x.x - y.x) * (x.x - y.x) + (x.y - y.y) * (x.y - y.y) )) ;
}

int cmp(const void * a ,const void * b)
{
	return (*(Edge *)a).dist > (* (Edge *)b).dist ;
}

void init() ;
int find_x(int x) ;
void join(int x , int y) ;
double kruskal() ;

int n ;
int num ;
int sal ;
int nnum ;
int nlen ;

int main()
{
	scanf("%d" , &n) ;
	
	while(n--)
	{
		scanf("%d %d" , &sal , &num) ;
		
		int i ;
		
		for(i = 0 ; i < num ; i ++)
			scanf("%d %d" , &point[i].x , &point[i].y) ;
		
		nnum = 0 ;
		
		int j ;
		
		for(i = 0 ; i < num ; i ++)
		{
			for(j = i + 1 ; j < num ; j ++)
			{
				edge[nnum].x = i ;
				edge[nnum].y = j ;
				edge[nnum].dist = dist_point(point[i] , point[j]) ;
				nnum ++ ;
			}
		}
		
		printf("%.2f\n" , kruskal()) ;
	}
	return 0 ;
}

void init()
{	
	int i ;
	for(i = 0 ; i < num ; i ++)
	{
		parent[i] = i ;
	}
}

int find_x(int x)
{
	int r = x ;
	
	while(parent[r] != r)
		r = parent[r] ;
	
	int i ;
	int j ;
	
	for(i = x ; parent[i] != r ;)
	{
		j = parent[i] ;
		parent[i] = r ;
		i = j ;
	}
	return r ;
}

void join(int x , int y)
{
	int p ;
	int q ;
	
	p = find_x(x) ;
	q = find_x(y) ;
	
	if(p < q)
		parent[q] = p ;
	else 
		parent[p] = q ;
}

double kruskal()
{
	init() ;
	
	qsort(edge , nnum , sizeof(edge[0]) , cmp) ;
	
	int i;
	nlen = 0 ;
	
	for(i = 0 ; i < nnum ; i ++)
	{
		if(find_x(edge[i].x) != find_x( edge[i].y))
		{
			join(edge[i].x , edge[i].y) ;
			key[nlen] = edge[i] ;
			nlen ++ ;
		}
	}
	
	return key[nlen - sal].dist ;
}





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值