前面题目给的一大堆修建条件其实可以忽略,对做题没有什么影响。
读完题目后,很容易就能发现这是一道最小生成树的题目,可以使用Prim或Kruskal来求解,不过在一看数据,好家伙,完全图,这肯定得用Prim啊。
不用说,先输入。
接下来,分析Prim。sum用来记录最终答案,dis数组用来保存当前节点至其他未经过的点的最短距离,vis数组保存已经过的点。
先进行初始化,起始点当然为1号城市,先用欧几里得距离计算公式计算出1号城市与其他城市之间的距离,同时,vis[1]也要置为1。
初始化后,循环n-1次,每次寻找其他未遍历过的节点中和当前节点距离最短的节点,将它标记为1,并将这条边的长度加到总长度中,以此节点为当前节点,继续循环。
这就是这道题的解题思路,最后上代码。
#include<bits/stdc++.h>
using namespace std;
struct node{
double x,y;
}a[5010];
int n;
bool vis[5010];
double dis[5010];
double prim(){
double sum=0;
vis[1]=1;
for(int i=2;i<=n;i++){
dis[i]=sqrt((a[1].x-a[i].x)*(a[1].x-a[i].x)+(a[1].y-a[i].y)*(a[1].y-a[i].y));
}
dis[0]=1e9;
for(int i=1;i<n;i++){
int k=0;
for(int j=1;j<=n;j++){
if(!vis[j]&&dis[j]<dis[k]){
k=j;
}
}
vis[k]=1;
sum+=dis[k];
for(int j=1;j<=n;j++){
double d=sqrt((a[k].x-a[j].x)*(a[k].x-a[j].x)+(a[k].y-a[j].y)*(a[k].y-a[j].y));
if(!vis[j]&&dis[j]>d){
dis[j]=d;
}
}
}
return sum;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lf %lf",&a[i].x,&a[i].y);
}
printf("%.2lf",prim());
return 0;
}
如果有什么不足,还请大佬们指出。