题目链接: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;
}


Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐