1 题面
2 分析
这题特别的地方就是边多,
5000
×
5000
5000\times 5000
5000×5000的边用kruscal空间不对.
主要空间瓶颈就是边的权是存不下来的,然而kruscal是需要计算然后再sort一遍的,我们想到prim.
其实prim算法我没有怎么选过,这题就当作prim练习题叭QAQ
3 具体实现
prim的主要思想就是对于已联通的点集
u
u
u与未联通的点集
v
v
v之间的所有边,选择一个最小的选上,这样就是最小的了.
那为什么这样是对的呢?
这里给出一个感性证明:对于每次选择,都将一个新点加入点集
u
u
u中,我们知道每个点都是要进入
u
u
u中的,而我们的算法又选的是最小的边,那么整个生成树一定就是最小的.
解释一下变量的意思:
pos代表从
u
u
u到
v
v
v新加入的那个点
vis[i]代表i是否在点集
u
u
u中
ans是最小生成树的大小
//dis是这一题要求的距离
void prim(){
int pos=0;
for (int i=1; i<=n; i++) {
double minx=inf;
for (int j=1; j<=n; j++) {
if (!vis[j] && dis[j]<minx) {
minx=dis[j];
pos=j;
}
}
ans+=minx;
vis[pos]=1;
for (int j=1; j<=n; j++) {
double d=cal(pos, j);
dis[j]=std::min(dis[j],d);
}
}
}
4 参考代码
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#define inf 99999999.0
#define maxn 5001
int n;
double dis[maxn],ans;
bool vis[maxn];
struct node{
int x,y;
}nodes[maxn];
double cal(int i,int j){
return sqrt((double)(nodes[i].x-nodes[j].x)*(nodes[i].x-nodes[j].x)+(double)(nodes[i].y-nodes[j].y)*(nodes[i].y-nodes[j].y));
}
void prim(){
int pos=0;
for (int i=1; i<=n; i++) {
double minx=inf;
for (int j=1; j<=n; j++) {
if (!vis[j] && dis[j]<minx) {
minx=dis[j];
pos=j;
}
}
ans+=minx;
vis[pos]=1;
for (int j=1; j<=n; j++) {
double d=cal(pos, j);
dis[j]=std::min(dis[j],d);
}
}
}
int main(){
scanf("%d",&n);
for (int i=1; i<=n; i++) {
scanf("%d%d",&nodes[i].x,&nodes[i].y);
dis[i]=inf;
}
dis[1]=0;
prim();
printf("%.2lf\n",ans);
return 0;
}