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的是一模一样的了。。。唉,换种说法就让我想了很久。。。看来还是理解不到位啊!