Prime算法构造最小生成树

最小生成树:包含图中全部顶点的极小联通子图。

极小:因为要取全部顶点,所以边要取最少,n个结点最少有n-1条边。边多了可能会导致回路,边少了会不连通。

Prime算法:加点法

假设顶点集V={v0,v1,v2,v3,v4},U是空集

(1)从顶点集V中任意选取一个顶点放入U,假设选取v0

则U={v0},V-U={v1 , v2 , v3 , v4 , v5 }

cost={(v0 , v1)34,(v0 , v2)46,(v0, v3)∞,(v0 , v4)∞,(v0, v5 )19}

 

 (2) 第一次迭代:

U={v0 , v5 },V-U={v1 , v2 , v3 , v4}

cost={(v0 , v1)34,(v5 , v2)25,(v5, v3)25,(v5 , v4)26} 

(3)第二次迭代:

U={v0 , v5 , v2 },V-U={v1 , v3 , v4 }

cost ={(v0 , v1)34, (v2, v3)17, (v5 , v4)26}

此时要找v1到U中顶点的最小权值,只需比较(v0,v1)25和(v2,v1)∞

此时要找v3到U中顶点的最小权值,只需比较(v5,v3)25和(v2,v3)17

此时要找v4到U中顶点的最小权值,只需比较(v5,v4)25和(v2,v4)∞

(4)第三次迭代:

U={v0 , v5, v2 , v3 },V-U={v1 ,  v4}

cost={(v0 , v1)34,(v5 , v4)26

 (5)第四次迭代:

U={v0 , v5, v2 , v3 , v4 },V-U={v1 }

cost ={(v4 , v1)12}

最终结果:

 

 

#include <iostream>

using namespace std;
class MGraph{
public:
    MGraph(char a[],int n,int e);
    void Prim(int v);
private:
    char vertex[100];//存放图中顶点
    int edge[100][100];//存放图中边
    int vertexNum,edgeNum;
    int MinEdge(int r[],int n);
};
MGraph::MGraph(char a[],int n,int e){
    int i,j,k,w;
    vertexNum=n;
    edgeNum=e;
    for(i=0;i<vertexNum;i++)//存储顶点
        vertex[i]=a[i];
    for(i=0;i<vertexNum;i++){//初始化邻接矩阵
        for(j=0;j<vertexNum;j++){
            if(i==j)
                edge[i][j]==0;
            else
                edge[i][j]=100;//假设边上的权值最大是100
        }
    }
    for(k=0;k<edgeNum;k++){
            cout<<"请输入边两个顶点的编号和边上的权值:"<<endl;
            cin>>i>>j>>w;
            edge[i][j]=w;
            edge[j][i]=w;
        }
}

void MGraph::Prim(int v){//从顶点v出发
    int i,j,k;
    int adjvex[100];//候选最短边的邻接点
    int lowcost[100];//候选最短边的权值
    lowcost[v]=0;//把顶点v加入集合U
    for(i=0;i<vertexNum;i++){
        lowcost[i]=edge[v][i];
        adjvex[i]=v;
    }
    for(k=1;k<vertexNum;k++){//迭代n-1次
        j=MinEdge(lowcost,vertexNum);//找出每次V-U到U的最小权值对应的j
        cout<<j<<" "<<adjvex[j]<<" "<<lowcost[j]<<endl;
        lowcost[j]=0;//把顶点j加入U
        for(i=0;i<vertexNum;i++){
                if(edge[i][j]<lowcost[i]){
                    lowcost[i]=edge[i][j];
                    adjvex[i]=j;
                  }
            }
      }
}

int MGraph::MinEdge(int r[],int n){
    int i,index=0;
    int min=100;//假设边上的权值最大是100
    for(i=1;i<n;i++){
        if(r[i]!=0&&r[i]<min){
            min=r[i];
            index=i;
        }
    }
    return index;
}
int main( )
{
	char ch[6]={'A','B','C','D','E','F'};
	MGraph mg(ch,6,9);
	mg.Prim(0);
	return 0;
}

运行结果
请输入边两个顶点的编号和边上的权值:
0 1 34
请输入边两个顶点的编号和边上的权值:
0 2 46
请输入边两个顶点的编号和边上的权值:
0 5 19
请输入边两个顶点的编号和边上的权值:
1 4 12
请输入边两个顶点的编号和边上的权值:
2 3 17
请输入边两个顶点的编号和边上的权值:
2 5 25
请输入边两个顶点的编号和边上的权值:
3 4 38
请输入边两个顶点的编号和边上的权值:
3 5 25
请输入边两个顶点的编号和边上的权值:
4 5 26

5 0 19
2 5 25
3 2 17
4 5 26
1 4 12

 

 

Prime算法是求解最小生成树的一种常用算法,其基本思想是从图中任意一个节点开始,每次选择与当前生成树中的节点相邻且权值最小的边,将其加入生成树,并将其相邻的节点加入到已访问的节点集合中,直到生成树中包含所有节点为止。 具体实现步骤如下: 1. 选择一个任意的起始节点,将其加入已访问节点集合visited中。 2. 遍历与已访问节点集合visited中的节点相邻的所有节点,找到权值最小的边,将其加入生成树中。 3. 将新加入的节点加入已访问节点集合visited中。 4. 重复步骤2和3,直到已访问节点集合visited中包含所有节点。 下面是伪代码实现: ``` // 定义节点和边的数据结构 struct Node { int id; // 节点编号 }; struct Edge { int from; // 起始节点编号 int to; // 目标节点编号 int weight; // 权值 }; vector<Node> nodes; // 所有节点 vector<Edge> edges; // 所有边 vector<int> visited(nodes.size(), 0); // 已访问节点 vector<Edge> mst; // 最小生成树 // 从start节点开始构建最小生成树 void prime(int start) { visited[start] = 1; // 将start节点加入已访问节点集合中 while (mst.size() < nodes.size() - 1) { // 生成树中边数为节点数-1 Edge min_edge = {0, 0, INT_MAX}; // 初始化权值最小边 for (Edge e : edges) { if (visited[e.from] ^ visited[e.to]) { // 如果边的两端节点一个已访问,一个未访问 if (e.weight < min_edge.weight) { // 选择权值最小的边 min_edge = e; } } } visited[min_edge.from] = visited[min_edge.to] = 1; // 将新加入的节点加入已访问节点集合中 mst.push_back(min_edge); // 将权值最小边加入生成树中 } } ``` 该算法的时间复杂度为O(n^2),其中n为节点数。如果使用堆优化可以将时间复杂度降为O(nlogn)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值