1.问题
举一个实例,画出采用Prim算法构造最小生成树的过程,并按实验报告模板编写算法。
举一个实例,画出采用Kruskal算法构造最小生成树的过程,并按实验报告模板编写算法。
2.解析
在一给定的无向图G = (V,E) 中,(u,v) 代表连接顶点u与顶点v的边,w(u, v) 代表此边的权,若存在 T 为 E 的子集且为无循环图,使得的 w(T) 最小,则此 T 为 G 的最小生成树。
Prim算法:
设最小生成树中的点的集合是U,开始时最小生成树为空,所以U为空。
Kruskal算法:
设最小生成树中边的集合为T,开始时最小生成树为空,所以T为空。
3.设计
Prime:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cctype>
#include<iomanip>
#include<map>
#include<vector>
#include<list>
#include<deque>
#include<stack>
#include<queue>
#include<set>
#include<cctype>
#include<string>
#include<stdexcept>
#include<fstream>
#include<sstream>
#include<sstream>
#define mem(a,b) memset(a,b,sizeof(a))
#define debug() puts("what the fuck!")
#define dedebug() puts("what the fuck!!!")
#define ll long long
#define ull unsigned long long
#define speed {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); };
using namespace std;
const double PI = acos(-1.0);
const int maxn = 2e5 + 10;
const int N = 2e3 + 10;
const ll INF = 1e18;
const ll mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const double esp_0 = 1e-6;
const double gold = (1 + sqrt(5)) / 2;
inline int rd() {
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch>'9') {
if (ch == '-')f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
ll quick(ll a, ll b) {
ll ans = 1;
while (b) {
if (b % 2) {
ans = ans * a % mod;
}
b >>= 1;
a = a * a % mod;
}
return ans % mod;
}
ll gcd(ll x, ll y) {
return y ? gcd(y, x % y) : x;
}
int n, m;
int g[110][110];
int dis[110];
int vis[110];
int prim() {
memset(vis, 0, sizeof vis);//标记数组
memset(dis, inf, sizeof dis);//最小生成树节点间距离
dis[1] = 0;
for (int i = 1; i < m; ++i) {
int pos = 0;
for (int j = 1; j <= m; ++j) {
if (!vis[j] && (pos == 0 || dis[j] < dis[pos]))pos = j;
}
vis[pos] = 1;
for (int j = 1; j <= m; ++j) {
if (!vis[j])dis[j] = min(dis[j], g[pos][j]);
}
}
int ans = 0;
for (int i = 1; i <= m; ++i) {
if (dis[i] == inf)return -1;//如果有一个点的dis值为inf,说明该点被孤立,原图不存在最小生成树
ans += dis[i];
}
return ans;//返回权值和
}
signed main() {
scanf("%d%d", &n, &m);
memset(g, inf, sizeof g);
for (int i = 1; i <= n; ++i) {
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
g[u][v] = g[v][u] = w;
}
int ans = prim();
cout << ans << endl;
return 0;
}
kruskal:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cctype>
#include<iomanip>
#include<map>
#include<vector>
#include<list>
#include<deque>
#include<stack>
#include<queue>
#include<set>
#include<cctype>
#include<string>
#include<stdexcept>
#include<fstream>
#include<sstream>
#include<sstream>
#define mem(a,b) memset(a,b,sizeof(a))
#define debug() puts("what the fuck!")
#define dedebug() puts("what the fuck!!!")
#define ll long long
#define ull unsigned long long
#define speed {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); };
using namespace std;
const double PI = acos(-1.0);
const int maxn = 2e5 + 10;
const int N = 2e3 + 10;
const ll INF = 1e18;
const ll mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const double esp_0 = 1e-6;
const double gold = (1 + sqrt(5)) / 2;
inline int rd() {
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch>'9') {
if (ch == '-')f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
ll quick(ll a, ll b) {
ll ans = 1;
while (b) {
if (b % 2) {
ans = ans * a % mod;
}
b >>= 1;
a = a * a % mod;
}
return ans % mod;
}
ll gcd(ll x, ll y) {
return y ? gcd(y, x % y) : x;
}
struct Edge {
int u, v, w;
Edge() {
};
Edge(int u, int v, int w) :u(u), v(v), w(w) {
};
bool operator<(const Edge& a) {
return w < a.w;
}
}edge[110];
int n, m;
int fa[110];
void init() {
for (int i = 1; i <= m; ++i)fa[i] = i;
}
int find(int x) {
return fa[x] == x ? x : find(fa[x]);
}
int uni(int x, int y) {
int fx = find(x);
int fy = find(y);
if (fx != fy) {
fa[fx] = fy;
return 1;
}
return 0;
}
int kruskal() {
int ans = 0;
init();
sort(edge + 1, edge + 1 + n);
for (int i = 1; i <= n; ++i) {
if (uni(edge[i].u, edge[i].v))
ans += edge[i].w;
}
return ans;
}
signed main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i) {
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
edge[i] = Edge(u, v, w);
}
printf("%d\n", kruskal());
return 0;
}
4.分析
prim:
未使用优先队列优化,需要遍历每一个点O(V2),并进行累加O(V),时间复杂度总共为O(V2+V),约为O(V2)
kruskal:对边排序时间复杂度约为O(Elog2E),并查集操作O(E),共为O(Elog2E+E),则约为O(Elog2E)