题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3405
【题目大意】
给你n个点的坐标,忽视其中一个点,求余下点的最小生成树。
我们不知道忽视的是哪一个点,所以要进行n次最小生成树。
prim算法需要使用一个标记数组 intree ,我们只要把忽视的那个点放入intree就不会扫描了;
【源代码】
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn = 55;
struct node{
int x,y;
}PP[maxn];
const double INF = 100000000.0;
double G[maxn][maxn];
bool intree[maxn];
double minDist[maxn];
int n;
double distane(node a,node b){
return sqrt((double)(a.x-b.x)*(a.x-b.x)+(double)(a.y-b.y)*(a.y-b.y));
}
double prim(int x){
double sum=0;
intree[x]=1;
if(x!=0){//如果忽视的点不是 0
for(int i=0;i<n;i++){ //起点置为 0
minDist[i]=G[i][0];
}
intree[0]=1;
}
else{ //否则
for(int i=0;i<n;i++){ //起点置为1
minDist[i]=G[i][1];
}
intree[1]=1;
}
for(int nodeNum=1;nodeNum<n-1;nodeNum++){ //注意这里要找的点只有n-2个点
double tmpMin=INF;
int addNode=-1;
for(int i=0;i<n;i++){
if(!intree[i]&&minDist[i]<tmpMin){
tmpMin = minDist[i];
addNode = i;
}
}
if(tmpMin==INF) {
return -1;
}
sum+=tmpMin;
intree[addNode]=1;
for(int i=0;i<n;i++){
if(!intree[i]&&G[addNode][i]<minDist[i])
minDist[i]=G[addNode][i];
}
}
if(sum!=0)
return sum;
return -1;
}
void init(){
for(int i=0;i<maxn;i++)
for(int j=0;j<maxn;j++)
G[i][j]=INF;
}
int main(){
int T;
scanf("%d",&T);
while(T--){
init();
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d%d",&PP[i].x,&PP[i].y);
}
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
double dis = distane(PP[i],PP[j]);
G[i][j]=min(G[i][j],dis);
G[j][i]=min(G[j][i],dis);
}
}
double ans=INF;
for(int i=0;i<n;i++){
memset(intree,0,sizeof(intree));
for(int j=0;j<maxn;j++)
minDist[j]=INF; //这里要初始化
double tmp = prim(i);
if(tmp!=-1)
ans=min(tmp,ans);
}
printf("%.2lf\n",ans);
}
return 0;
}