Prim算法:每次找距离集合V'的最近的点 + 松弛操作( dis[j] = min(dis[j] , map[k][j]) )
prim的松弛操作和迪杰斯特拉的松弛操作不一样,不要混淆了!
Vector + 优先队列实现
#include <stdio.h> #include <string.h> #include <algorithm> #include <vector> #include <queue> #define MAX 50005 #define INF 0x3f3f3f3f using namespace std; typedef struct Node{ int v; //边的终点 int w; //权值 }Node; struct cmp{ //重载比较运算符,用于优先队列的排序 bool operator()(Node a,Node b){ return a.w>b.w; } }; vector<Node> map[MAX]; priority_queue <Node, vector<Node>, cmp >q; //用优先队列优化 int vis[MAX]; //是否被访问过 int dis[MAX]; //该集合到所有点的最短距离 int n,m; void prim(){ memset(dis,INF,sizeof(dis)); memset(vis,0,sizeof(vis)); dis[1]=0; max_dis; int min_,k; Node node1; //加入第一个结点 node1.v=1; node1.w=0; q.push(node1); while(!q.empty()){ Node node=q.top(); //每次取优先队列的队头 q.pop(); int v=node.v; int w=node.w; vis[v]=1; for(int j=0;j<map[v].size();j++){ //更新与v点相邻的点v到集合V'的最短距离 int v_=map[v][j].v; int w_=map[v][j].w; if(!vis[v_]){ if(dis[v_]>w_){ //点v没有被访问过且点v到点k的距离小于点v到集合V'的距离 dis[v_]=w_; Node node_; node_.v=v_; node_.w=w_; q.push(node_); } } } } } int main(){ int root; int u,v,w; while(scanf("%d",&n)!=EOF){ scanf("%d",&m); scanf("%d",&root); for(int i=1;i<=n;i++) map[i].clear(); for(int i=0;i<m;i++){ scanf("%d %d %d",&u,&v,&w); Node node1,node2; node1.v=v; node1.w=w; map[u].push_back(node1); node2.v=u; node2.w=w; map[v].push_back(node2); } prim(); } return 0; }
Vector实现
#include <stdio.h> #include <string.h> #include <algorithm> #include <vector> #define MAX 50005 #define INF 0x3f3f3f3f using namespace std; typedef struct Node{ int v; int w; }Node; vector<Node> map[MAX]; int vis[MAX]; //是否被访问过 int dis[MAX]; //该集合到所有点的最短距离 int n,m; void prim(){ memset(dis,INF,sizeof(dis)); memset(vis,0,sizeof(vis)); dis[1]=0; int min_,k; for(int i=1;i<=n;i++){ //依次加入每一个顶点 min_=INF; k=-1; for(int j=1;j<=n;j++){ if(!vis[j] && dis[j]<min_){ //找当前不在集合V'内且与集合V'最近的一个点 min_=dis[j]; k=j; } } if(k==-1) return ; //图不连通 vis[k]=1; for(int j=0;j<map[k].size();j++){ //更新与k点相邻的点v到集合V'的最短距离 int v=map[k][j].v; int w=map[k][j].w; if(!vis[v]){ if(dis[v]>w){ //点v没有被访问过且点v到点k的距离小于点v到集合V'的距离 dis[v]=w; } } } } } int main(){ int root; int u,v,w; while(scanf("%d",&n)!=EOF){ scanf("%d",&m); for(int i=1;i<=n;i++) map[i].clear(); for(int i=0;i<m;i++){ scanf("%d %d %d",&u,&v,&w); Node node1,node2; node1.v=v; node1.w=w; map[u].push_back(node1); node2.v=u; node2.w=w; map[v].push_back(node2); } prim(); } return 0; }
二维数组实现 (50000 *50000 用不了二维数组)
#include <stdio.h> #include <string.h> #include <algorithm> #define MAX 1000 #define INF 0x3f3f3f3f using namespace std; int map[MAX][MAX]; int vis[MAX]; //是否被访问过 int dis[MAX]; //该集合到所有点的最短距离 int n,m; void prim(){ memset(dis,INF,sizeof(dis)); memset(vis,0,sizeof(vis)); dis[1]=0; int min_,k; for(int i=1;i<=n;i++){ //依次加入每一个顶点 min_=INF; k=-1; for(int j=1;j<=n;j++){ if(!vis[j] && dis[j]<min_){ //找当前不在集合V'内且与集合V'最近的一个点 min_=dis[j]; k=j; } } if(k==-1) return ; //图不连通 vis[k]=1;for(int j=1;j<=n;j++){ //更新与k点相邻的点v到集合V'的最短距离 if(!vis[j]){ if(dis[j]>map[k][j]){ //点v没有被访问过且点v到点k的距离小于点v到集合V'的距离 dis[j]=map[k][j]; } } } } }