中國大學MOOC-陳越、何欽銘-資料結構-2018秋——公路村村通
阿新 • • 發佈:2018-12-05
我的中國大學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++解題報告: