codeforce_exercise_r32

DDL 的恐惧 :

问题描述

题目简述

国防部计划用无线网络连接若干个边防哨所。2 种不同的通讯技术用来搭建无线网络;
每个边防哨所都要配备无线电收发器;有一些哨所还可以增配卫星电话。
任意两个配备了一条卫星电话线路的哨所(两边都有卫星电话)均可以通话,无论他们相距多远。而只通过无线电收发器通话的哨所之间的距离不能超过 D,这是受收发器的功率限制。收发器的功率越高,通话距离 D 会更远,但同时价格也会更贵。
收发器需要统一购买和安装,所以全部哨所只能选择安装一种型号的收发器。换句话说,每一对哨所之间的通话距离都是同一个 D。你的任务是确定收发器必须的最小通话距离 D,使得每一对哨所之间至少有一条通话路径(直接的或者间接的)。

输入/输出格式

输入格式:
输入数据第 1 行,2 个整数 S 和 P,S 表示可安装的卫星电话的哨所数,P 表示边防哨所的数量。接下里 P 行,每行两个整数 x,y 描述一个哨所的平面坐标(x, y),以 km 为单位。
输出格式:
第 1 行,1 个实数 D,表示无线电收发器的最小传输距离,精确到小数点后两位。

样例

输入样例:
2 4
0 100
0 300
0 600
150 750
输出样例:
212.13

问题分析

解题思路

这个题首先很明显需要先求出最小生成树。但是,进一步的由于有卫星电话的关系,只要多于两个哨所可以安装卫星电话,就相当于在这两个哨所之间连接了一条权值为0的边。这里不要把加入很多边合起来看,这样太复杂。如果单看加入一条边,那么很容易发现,将该边加入后,这条边可以替换掉所在环上的权值最大的边。那么根据以上思路,当有s个哨所可以安装卫星电话时,一定可以替换掉最小生成树上的最大的s-1条边。因此,结果也就很明显了。

参考代码
#include <iostream>
#include <queue>
#include <cstring>
#include <vector>
#include <cmath>

using namespace std;

class edge
{
public:
	int from;
	int to;
	float weight;
	edge(int u,int v,float w)
	{
		from=u;
		to=v;
		weight=w;
	}
	bool operator <(const edge& e) const
	{
		return weight>e.weight;
	}
};

class point
{
public:
	int p_x;
	int p_y;
	point(int xx,int yy)
	{
		p_x=xx;
		p_y=yy;
	}
};

priority_queue<edge> pq;
vector<edge> edges;
vector<point> points;
int p[510];
int eq[510];
int s,u;

void init()
{
	memset(eq,0,sizeof(eq));
	while(!pq.empty()) pq.pop();
	edges.clear();
	points.clear();
	for(int i=0;i<510;i++)
	{
		p[i]=i;
	}
}

void addedge(int index)
{
	point p1=points[index];
	for(int i=0;i<index;i++)
	{
		point p2=points[i];
		float dist=sqrt((p1.p_x-p2.p_x)*(p1.p_x-p2.p_x)+(p1.p_y-p2.p_y)*(p1.p_y-p2.p_y));
		edge te(i,index,dist);
		//printf("add edge (%d %d %f)\n",te.from,te.to,te.weight);
		pq.push(te);
	}
}

int find(int u)
{
	if(p[u]!=u) p[u]=find(p[u]);
	return p[u];
}

void kruskal()
{
	int cnt=0;
	while(cnt!=u-1)
	{
		edge te=pq.top();
		pq.pop();
		//printf("get edge (%d %d %f)\n",te.from,te.to,te.weight);
		int a=find(te.from);
		int b=find(te.to);
		//printf("a=%d b=%d\n",&a,&b);
		if(a!=b) 
		{
			edges.push_back(te);
			p[a]=b;
			cnt++;
		}
	}
}

int main()
{
	init();
	scanf("%d %d",&s,&u);
	for(int i=1;i<=u;i++)
	{
		int x,y;
		scanf("%d %d",&x,&y);
		point tp(x,y);
		points.push_back(tp);
		addedge(points.size()-1);
	}
	kruskal();
	printf("%.2f",edges[edges.size()-1-s+1].weight);
	return 0;
}

心得体会

其实突然想到,换个理解思路可能会更好:s个点可以连接卫星,那么这s个点之间用卫星连接后,剩下的点用无线电连接,就相当于取出最小生成树的前p-s条边即可。这样看来,这个题不就和r31的是一模一样的了。。。唉,换种说法就让我想了很久。。。看来还是理解不到位啊!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值