[图论]剑鱼行动:prim

剑鱼行动


Description

给出N个点的坐标,对它们建立一个最小生成树,代价就是连接它们的路径的长度,现要求总长度最小。N的值在100以内,坐标值在[-10000,10000].结果保留二位小数


Input

N个点 ,N个点的坐标


Output

连接它们的最短路径的长度


Sample Input

5 ---------------5个点
0 0 ---------------5个点点的坐标
0 1
1 1
1 0
0.5 0.5


Sample Output

2.83


解析

这道题一看就是最小生成树,有两种方法,分别为
普里姆算法(prim

克鲁斯卡尔(kruskal
本题解使用的是 prim
Prim算法采用与DijkstraBellman-Ford算法一样的“蓝白点”思想:白点代表已经进入最小生成树的点,蓝点代表未进入最小生成树的点。


难点

题目给出的可能是小数,所以就有了我们的读入方式
aj[i][1]储存x坐标,a[j][2]储存y坐标

for(int i=1;i<=n;i++)scanf("%lf%lf",&aj[i][1],&aj[i][2]);

以及我们的计算距离公式,原理是勾股定理

sqrt((abs(aj[i][1]-aj[j][1]))*(abs(aj[i][1]-aj[j][1]))+(abs(aj[i][2]-aj[j][2]))*(abs(aj[i][2]-aj[j][2])));

代码

模板解析

#include<cmath>
#include<stdio.h>
#include<iostream>
using namespace std;
int n,u[10005],o,p,q;
double ans,minn[10005],aj[10005][3],a[10005][10005];
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%lf%lf",&aj[i][1],&aj[i][2]); //神奇的读入
	for(int i=1;i<=n;i++){ //神奇的处理
		for(int j=1;j<n;j++){
			a[i][j]=sqrt((abs(aj[i][1]-aj[j][1]))*(abs(aj[i][1]-aj[j][1]))+(abs(aj[i][2]-aj[j][2]))*(abs(aj[i][2]-aj[j][2])));
			a[j][i]=a[i][j];
		}
	}
	memset(minn,0x7f,sizeof(minn)); //愉快地套我们的模板,解析链接在上面
	minn[1]=0;
	memset(u,true,sizeof(u));
	for(int i=1;i<=n;i++){
		o=false;
		for(int j=1;j<=n;j++)
			if(u[j] and (minn[j]<minn[o]))
				o=j;
		u[o]=0;
		for(int j=1;j<=n;j++)
			if(u[j] and (a[o][j]<minn[j])){
				minn[j]=a[o][j];

			}
				
	}
	for(int i=1;i<=n;i++)
		ans+=minn[i];
	printf("%.2lf",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/luojunhang/p/12300149.html