题意:
给出一些点的坐标, 求这些点之间的第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; }