图论 经典prim算法(MST)

来源:互联网 发布:域名历史记录查询 编辑:程序博客网 时间:2024/05/01 15:24

刚学了prim,写了prim算法最经典的问题,

给出n点,求点阵中最小生成树,代码如下:

#include<iostream>#include<cmath>#include<cstdio>using namespace std;const int MAX=100+5;const double INF=0x7ffffff;struct node{double x,y;}e[MAX];bool vis[MAX];double map[MAX][MAX];double dist[MAX];double dis(struct node a,struct node b){return sqrt((a.x-b.x)*(a.x-b.x)*1.0+(a.y-b.y)*(a.y-b.y));}double prim(int n){int i,j,mark;double temp,ans;memset(vis,0,n+2);p[1]=1;ans=0;//定初始顶点为1,vis[1]=1;for(i=2;i<=n;i++)dist[i]=map[1][i];for(i=2;i<=n;i++){temp=INF; for(j=1;j<=n;j++)if(vis[j]==0&&dist[j]<temp){mark=j;temp=dist[j];}vis[mark]=1;//标记已访问ans+=dist[mark];for(j=1;j<=n;j++)//更新顶点if(!vis[j]&&map[mark][j]>=0&&map[mark][j]<dist[j])dist[j]=map[mark][j];//dist【】存储未访问点与集合最小距离,此处更新该数组}return ans;}int main(){int N,n,i,j;double ans;cin>>N;while(N--){cin>>n;for(i=1;i<=n;i++)cin>>e[i].x>>e[i].y;for(i=1;i<=n;i++)for(j=i;j<=n;j++)map[i][j]=map[j][i]=dis(e[i],e[j]);ans=prim(n);cout<<ans<<endl;}return 0;}

额,下面附上我刚开始做的代码,复杂度较高。

分析:用node e[MAX}存储所有点,矩阵dist[i][j]存储点i与点j的距离,用p[MAX]来存储已加入集合的点,vis[MAX]标记该点是否被访问(另开数组而不遍历p【】,出于节约时间考虑),循环n-1次,每次寻找到集合中的点(既p【i】)与未加入集合点距离最小值,{将其并入集合p,并标记访问vis,加入结果ans}

#include<iostream>#include<cmath>#include<cstdio>using namespace std;const int MAX=100+5;const double INF=0x7ffffff;struct node{double x,y;}e[MAX];bool vis[MAX];int p[MAX];double dist[MAX][MAX];double dis(struct node a,struct node b){return sqrt((a.x-b.x)*(a.x-b.x)*1.0+(a.y-b.y)*(a.y-b.y));}double prim(int n){int i,j,k,mark;double temp,ans;memset(p,0,n+2);memset(vis,0,n+2);p[1]=1;ans=0;vis[1]=1;for(i=2;i<=n;i++){temp=INF;for(j=1;j<i;j++)//用寻找集合中的点与未加入加入集合点距离最小值{for(k=1;k<=n;k++){if(vis[k]==0&&dist[p[j]][k]<temp){mark=k;temp=dist[p[j]][k];}}}vis[mark]=1;p[i]=mark;ans+=temp;}return ans;}int main(){int N,n,i,j;double ans;cin>>N;while(N--){cin>>n;for(i=1;i<=n;i++)cin>>e[i].x>>e[i].y;for(i=1;i<=n;i++)for(j=i;j<=n;j++)dist[i][j]=dist[j][i]=dis(e[i],e[j]);ans=prim(n);cout<<ans<<endl;}return 0;}


0 0