题意:
给出一些点的坐标, 求这些点之间的第k长边.
本来的描述是, 一些点, 有效距离之内可以传送数据, 有效距离也表示耗电量. 可以放k个收发器, 收发器的有效距离无穷大. 所有点的耗电量设为相同, 问此时单点耗电量最小是多少.
思路:
先求最小生成树, 放k个传感器的话, 可以省去k-1条边(就是直接发走而不需要走这条边), 那么求出第k长边即可.
特殊的,未加优化的prim:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <stack>
#include <queue>
#include <algorithm>
#include <iostream>
using namespace std;
#define Maxn 100005
#define INF 0x3f3f3f3f
struct Point
{
double x,y;
}point[Maxn];
double dist[Maxn];
int vis[Maxn];
int s,p;
int m;
double ans[Maxn];
double getDis(Point a,Point b)
{
return sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y));
}
/**
prim算法的基本思路:
MST点集A和未加入MST点集~A, 每次从~A中找到到A中的点距离最近的点, 加入A. 重复这个过程, 直到~A为空.
要点是找到那个"距离最近的点"
*/
void prim()
{
dist[0] = 0;//每次都从0这个点出发
for(int i=1;i<p;i++)
{
dist[i] = INF;//初始化为正无穷, 还没开始扩展
}
memset(vis,0,sizeof(vis));//都未拜访
m = 0;//ans的游标
for(int i=0;i<p;i++)//遍历每一个点,i
{
double mi = INF;
int mik;//存最近距离和最近点
for(int j=0;j<p;j++)//遍历每一个点,j
{
if(dist[j]<mi && !vis[j]) mi = dist[j],mik = j;//找到最近距离和最近点,通过初始化启动算法
}//dist[j]表示j点到A集合的最小距离.
ans[m++] = mi;
vis[mik] = 1;
for(int j=0;j<p;j++)//本题比较特殊,给的是点,可以直接计算邻接的边,松弛.
{//mik是新加点, 每次只需更新这一点.
if(dist[j]> getDis(point[mik],point[j])) dist[j] = getDis(point[mik],point[j]);
}
}
}
int main()
{
int w;
double a,b;
scanf("%d",&w);
while(w--)
{
p = 0;
scanf("%d",&s);
while(scanf("%lf",&a)==1 && a!=-1)
{
scanf("%lf",&b);
point[p].x = a,point[p].y = b;
p++;
}
prim();
sort(ans+1,ans+m);
//第一条边是0号点与MST所在连通分量的距离,为0,不参加边长的比较
//m已经++过了,故可以直接用+m作为end指针.
printf("%.0f\n",ceil(ans[p-s]));
}
return 0;
}