版权声明:我的GitHub:https://github.com/617076674。真诚求星! https://blog.csdn.net/qq_41231926/article/details/84674573
我的中国大学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++解题报告: