zoukankan      html  css  js  c++  java
  • 重学数据结构系列之——图论算法之Prim算法

    学习来源:计蒜客

    1.首先了解一些概念:

    生成树:一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边。(简单来说就是顶点不变,但边数是n-1条,而且抽取出来后,图还是连通的)
    最小生成树:如何从一个带权图中抽出一棵生成树,使得边权值和最小,这棵生成树就叫做最小生成树。(就是找生成树中权值之和最小的)


    2.Prim算法


    即普里姆算法,简单来说就是从一个点出发,每次取出了生成树中的边以外最小的边

    Prim 算法一般应用于边较为稠密的图,也就是顶点较少、而边较多的图。


    3.代码实现

    #include <iostream>
    #include <cstring>
    #include <vector>
    #include <queue>
    
    using namespace std;
    //定义一个大整数,下面表示距离很远就对了
    const int INF = 0x3f3f3f3f;
    
    //一个边的结构
    struct Edge {
    	//vertex:一条边的另一个端点
    	//weight:该边权重
    	int vertex, weight;
    };
    
    class Graph{
    private:
    	int n;
    	bool *visited;
    	vector<Edge> *edges; //邻接表
    public:
    	//dist(distance)://用于保存某个顶点到生成树的距离
    	int *dist;
    	Graph(int input_n){
    		n = input_n;
    		edges = new vector<Edge>[n];
    		dist = new int[n];
    		memset(visited, 0, n * sizeof(bool));
    		//初始化每个dist为0x3f3f3f3f,这是个大整数,表示距离很远
    		memset(dist,0x3f, n * sizeof(int));
    	}
    	~Graph(){
    		delete[] dist;
    		delete[] visited;
    		delete[] edges;
    	}
    	void insert(int x, int y, int weight) {
    		Edge edge1,edge2;  
    <span style="white-space:pre">		</span>edge1.vertex = x;  
    <span style="white-space:pre">		</span>edge1.weight = weight;  
    <span style="white-space:pre">		</span>edge2.vertex = y;  
    <span style="white-space:pre">		</span>edge2.weight = weight;  
    <span style="white-space:pre">		</span>edges[x].push_back(edge2);  
    <span style="white-space:pre">		</span>edges[y].push_back(edge1);
    	}
    
    	//v:起点
    	int prim(int v){
    		//定义并初始化总权值为0
    		int total_weight = 0;
    		//起点距离起点的距离为0
    		dist[v] = 0;
    		for (int i = 0; i < n; i++) {//外层循环是要找到n个顶点
    			int min_dist = INF, min_vertex; //初始化最小距离为一个大的整数,min_vertex为最小距离的那个点的编号
    			//从n个点中找最近的顶点(离生成树最近的),i=0时,当然是起点自己离自己(暂时生成树只有起点)最近啦,而且我们初始化其距离为0了,下一个循环是更新这个点连着的边 另外一个端点的距离为其边的权值
    			for (int j = 0; j < n; j++) {
    				//若没访问过,且距离小于最小距离
    				if (!visited[j] && dist[j] < min_dist) {
    					//更新最小距离
    					min_dist = dist[j];
    					//保存最小的顶点的编号
    					min_vertex = j;
    				}
    			}
    			//加上最小距离(权值)
    			total_weight += min_dist;
    			//设置为已访问
    			visited[min_vertex] = 1;
    			//枚举这个结点的所有的边
    			for(Edge &j : edges[min_vertex]){
    				//如果边的另一个端点没访问过且权值小于距离
    				if(!visited[j.vertex] && j.weight < dist[j.vertex]){
    					//就更新其距离为边的权值
    					dist[j.vertex] = j.weight;
    				}
    			}
    		}
    		return total_weight;
    	}
    };
    
    int main() {
    	int n, m;
    	cin >> n >> m;
    	Graph g(n);
    	for (int i = 0; i < m; i++) {
    		int a, b, c;
    		cin >> a >> b >> c;
    		g.insert(a, b, c);
    	}
    	cout << g.prim(0) << endl;
    	return 0;
    }



    运行环境:

    C++11

    输入按照下图输入




  • 相关阅读:
    关于两次指针(struct型)传参数的问题
    git学习基础教程
    程序员恶性循环- 有感
    基于Tomcat 的WEB Project存在的安全漏洞总结
    使用Maven自动部署Java Web项目到Tomcat问题小记
    MyEclipse中Maven的配置
    mybatis处理集合、循环、数组和in查询等语句的使用
    JBOSS的启动和停止
    myeclipse越来越卡了怎么回事啊?
    linux shell 模拟post请求
  • 原文地址:https://www.cnblogs.com/cnsec/p/13286541.html
Copyright © 2011-2022 走看看