C++實現Prim演算法

qq_46027243發表於2020-10-02

1,基本原理

MST性質:設 N =(V,E)是一個連通圖,U是頂點集V的一個非空子集。若邊(u,v)是一條具有最小權值的邊,其中u屬於U,v屬於V-U,則必存在一棵包含邊(u,v)的最小生成樹。

舉例:在這裡插入圖片描述
如圖,從v1點開始,將v1點加入到U中,尋找從U到V-U的權值最小的邊,為1,將v3加入U中,再次尋找從U到V-U的權值最小的邊,為2,將v4加入到U中,再次尋找從U到V-U的權值最小的邊,為2,將v5加入到U中,再次尋找從U到V-U的權值最小的邊,為3,將v2加入到U中,最小生成樹完成。結果如下:在這裡插入圖片描述

2,具體程式碼實現

注:這裡因為把各個資料組都定義在了Prim函式裡,所以顯得函式體比較臃腫,其實主要程式碼只有兩部分,一是更新從U到V-U中各點的最短邊,二是尋找從U到V-U的最短邊。

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
#define Max  999999

void Prim(vector<vector<int> > V)
{
	vector<int> d;  //記錄從U到V-U中各點的最短邊
	vector<int> U;  //記錄被加入到U中的點
	vector<bool> visited;  //記錄點是否被加入U中
	vector<int> M;  //記錄最終得到的各條邊
	d.resize(V.size());
	visited.resize(V.size());
	fill(visited.begin(), visited.end(), false);

	U.push_back(0);
	visited[0] = true;
	fill(d.begin(), d.end(), Max);
	d[0] = 0;
	while (U.size() < V.size())
	{
		int x = U[U.size() - 1];         
		for (int i = 0; i < d.size(); ++i)  //更新從U到V-U中各點的最短邊
		{
			if (!visited[i] && V[x][i] < d[i])
			{
				d[i] = V[x][i];
			}
		}
		int min = Max;
		int index = 0;
		for (int i = 0; i < d.size(); ++i)   //尋找從U到V-U的最短邊
		{
			if (d[i] < min && !visited[i])
			{
				min = d[i];
				index = i;
			}
		}
		if (index == 0)
		{
			cout << "該圖不連通" << endl;
			return;
		}
		visited[index] = true;
		U.push_back(index);
		M.push_back(min);
	}
	for (int i = 0; i < M.size(); ++i)  //輸出所得最小生成樹的各條邊
	{
		cout << M[i] << "  ";
	}
}

int main()
{
	int n = 0;
	int m = 0;
	int u, v, w;
	cout << "輸入節點個數:" << endl;
	cin >> n;
	cout << "輸入邊數:" << endl;
	cin >> m;
	vector<vector<int> > V;
	V.resize(n);
	for (int i = 0; i < n; ++i)
	{
		V[i].resize(n);
		for (int j = 0; j < n; ++j)
		{
			V[i][j] = Max;
		}
	}
	cout << "輸入各條邊的資訊:" << endl;
	for (int i = 0; i < m; ++i)
	{
		cin >> u >> v >> w;
		V[u][v] = V[v][u] = w;
	}
	Prim(V);

	return 0;
}

輸入輸出資訊:在這裡插入圖片描述

相關文章