1. 程式人生 > >中國大學MOOC-陳越、何欽銘-資料結構-2018秋——公路村村通

中國大學MOOC-陳越、何欽銘-資料結構-2018秋——公路村村通

我的中國大學MOOC-陳越、何欽銘-資料結構-2018秋程式碼倉:https://github.com/617076674/MOOC-DataStructure-2018-Autumn

題目描述:

知識點:最小生成樹

思路一:prim演算法

prim演算法的具體實現:

prim演算法需要實現兩個關鍵的概念,即集合S的實現、頂點Vi(1 <= i <= N)與集合S的最短距離。

(1)集合S的實現方法和Dijkstra中相同,即使用一個bool型陣列visited[]表示頂點是否已被訪問。其中visited[i] == true表示頂點Vi已被訪問,visited[i] == false表示頂點Vi未被訪問。

(2)令int型陣列d[]來存放頂點Vi(1 <= i <= N)與集合S的最短距離。初始時除了起點s的d[s]賦為0,其餘頂點都賦為一個很大的數來表示INF,即不可達。

時間複雜度是O(N ^ 2)。空間複雜度是O(N + M)。

C++程式碼:

#include<iostream>
#include<vector>

using namespace std;

struct node{
	int v, price;
	node(int _v, int _price){
		v = _v;
		price = _price;
	}
};

int N, M, d[1001], INF = 1000000000;
vector<node> graph[1001];
bool visited[1001];

int prim(); 

int main(){
	scanf("%d %d", &N, &M);
	fill(visited + 1, visited + N + 1, false);
	fill(d + 1, d + N + 1, INF);
	int v1, v2, price;
	for(int i = 0; i < M; i++){
		scanf("%d %d %d", &v1, &v2, &price);
		graph[v1].push_back(node(v2, price));
		graph[v2].push_back(node(v1, price));
	}
	int result = prim();
	printf("%d\n", result);
	return 0;
}

int prim(){
	d[1] = 0;
	int ans = 0;
	for(int i = 0; i < N ; i++){
		int u = -1, min = INF;
		for(int j = 1; j <= N; j++){
			if(!visited[j] && d[j] < min){
				u = j;
				min = d[j];
			}
		}
		if(u == -1){
			return -1;
		}
		d[u] = min;
		visited[u] = true;
		ans += d[u];
		for(int j = 0; j < graph[u].size(); j++){
			int v = graph[u][j].v;
			int len = graph[u][j].price;
			if(!visited[v] && len < d[v]){
				d[v] = len;
			}
		}
	}
	return ans;
}

C++解題報告:

思路二:kruskal演算法

kruskal演算法的基本思想為:在初始狀態隱去圖中的所有邊,這樣圖中每個頂點都自成一個連通塊。之後執行下面的步驟:

(1)對所有邊按邊權從小到大進行排序。

(2)按邊權從小到大測試所有邊,如果當前測試邊所連線的兩個頂點不在一個連通塊中,則把這條測試邊加入當前最小生成樹中;否則,將邊捨棄。

(3)執行步驟(2),直到最小生成樹中的邊數等於總頂點數減1或是測試完所有邊時結束。而當結束時如果最小生成樹的邊數小於總頂點數減1,說明該圖不連通,返回-1。

時間複雜度是O(MlogM)。空間複雜度是O(M)。

C++程式碼:

#include<iostream>
#include<vector>
#include<algorithm>

using namespace std;

struct edge{
	int u, v, cost;
	edge(int _u, int _v, int _cost){
		u = _u;
		v = _v;
		cost = _cost;
	}
};

int N, M;
vector<edge> edges;
int father[1001]; 

int findFather(int x);
int kruskal();
bool cmp(edge e1, edge e2);

int main(){
	scanf("%d %d", &N, &M);
	for(int i = 1; i <= N; i++){
		father[i] = i;
	}
	int v1, v2, cost;
	for(int i = 0; i < M; i++){
		scanf("%d %d %d", &v1, &v2, &cost);
		edges.push_back(edge(v1, v2, cost));
	}
	int result = kruskal();
	printf("%d\n", result);
	return 0;
} 

int findFather(int x){
	int a = x;
	while(x != father[x]){
		x = father[x];
	}
	while(a != father[a]){
		int z = a;
		a = father[a];
		father[z] = x;
	}
	return x;
}

int kruskal(){
	int ans = 0, num_edge = 0;
	sort(edges.begin(), edges.end(), cmp);
	for(int i = 0; i < M; i++){
		int uFather = findFather(edges[i].u);
		int vFather = findFather(edges[i].v);
		if(uFather != vFather){
			father[uFather] = vFather;
			ans += edges[i].cost;
			num_edge++;
			if(num_edge == N - 1){
				break;
			}
		}
	}
	if(num_edge != N - 1){
		return -1;
	}
	return ans;
}

bool cmp(edge e1, edge e2){
	return e1.cost < e2.cost;
}

C++解題報告: