洛谷P1265 公路修建——最小生成树,prim算法,不存图,边算边求MST

题目:https://www.luogu.org/problemnew/show/P1265

分析:

本质是求最小生成树。对于规则2,构成环则申请时去掉最大边。

因为最多有5000个点,又是完全图,故不采用Kruskal算法。

用Prim算法时,用邻接矩阵则会MLE。只有涉及到松驰点的权值时,再计算边长。

易错点:

计算两点间距离时,因为点的坐标是整数,因此要将坐标平方进行类型强制转换。

double value(int i,int j){
	return sqrt( (double)(x[i]-x[j])*(x[i]-x[j]) + (double)(y[i]-y[j])*(y[i]-y[j]) );
}

也可以写成:

double value(int i,int j){
	return sqrt(1.0*(x[i]-x[j])*(x[i]-x[j]) + 1.0*(y[i]-y[j])*(y[i]-y[j]) );
}

注:

1.0*10,结果是double型的10;

但10*1.0,结果什么呢?

如果写成:

double value(int i,int j){
	return sqrt( (x[i]-x[j])*(x[i]-x[j]) + (y[i]-y[j])*(y[i]-y[j]) );
}

则卡掉9个点。

AC代码:

#include
#include
#include
#include
using namespace std;
int m,x[5001],y[5001];
int vis[5001];
double dis[5001],dist;
double ans=0;
double value(int i,int j){
	return sqrt( (double)(x[i]-x[j])*(x[i]-x[j]) + (double)(y[i]-y[j])*(y[i]-y[j]) );
}
void prim(){
	for(int i=1;i<=m;i++)dis[i]=1e20;
	dis[1]=0;
	int V=1;
	for(int i=1;i<=m;i++){
		double minn=1e20;
		for(int j=1;j<=m;j++)
			if(!vis[j])
				if(minn>dis[j]){
					minn=dis[j];
					V=j;
				}
		vis[V]=1;
		ans+=dis[V];
		for(int j=1;j<=m;j++)
			if(!vis[j]){
				dist=value(V,j);
				if(dis[j]>dist)dis[j]=dist;
			}
	}
}
int main(){
	cin>>m;
	for(int i=1;i<=m;i++)cin>>x[i]>>y[i];
	prim();
	printf("%.2f\n",ans);
	return 0;
}

 

你可能感兴趣的:(洛谷P1265 公路修建——最小生成树,prim算法,不存图,边算边求MST)