From 348d596fff4199af73c5bab2add940729fbf0728 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B5=B7?= <10402852@qq.com> Date: Mon, 8 Jan 2024 14:49:15 +0800 Subject: [PATCH] 'commit' --- TangDou/AcWing/MinimalSpanningTree/1146.md | 63 ++++++++++--------- .../MinimalSpanningTree/1146_Kruskal.cpp | 34 +++++----- .../AcWing/MinimalSpanningTree/1146_Prim.cpp | 29 +++++---- 3 files changed, 68 insertions(+), 58 deletions(-) diff --git a/TangDou/AcWing/MinimalSpanningTree/1146.md b/TangDou/AcWing/MinimalSpanningTree/1146.md index b932a4d..f2446f6 100644 --- a/TangDou/AcWing/MinimalSpanningTree/1146.md +++ b/TangDou/AcWing/MinimalSpanningTree/1146.md @@ -63,18 +63,19 @@ $1≤n≤300,0≤v_i,p_i,j≤10^5$ #include using namespace std; const int N = 310; -const int INF = 0x3f3f3f3f; int n; // n条顶点 int res; // 最小生成树的权值和 -int el; // 边数 + // Kruskal用到的结构体 const int M = 2 * N * N; // 无向图*2,稠密图N*N struct Edge { - int a, b, w; + int a, b, c; const bool operator<(const Edge &t) const { - return w < t.w; + return c < t.c; } -} e[M]; +} edge[M]; +int el; // 边数 + // 并查集 int p[N]; int find(int x) { @@ -84,39 +85,40 @@ int find(int x) { // Kruskal算法 int kruskal() { // 按边的权重排序 - sort(e, e + el); + sort(edge, edge + el); // 初始化并查集,注意并查集的初始是从0开始的,因为0号是超级源点 for (int i = 0; i <= n; i++) p[i] = i; // 枚举每条边 for (int i = 0; i < el; i++) { - int a = e[i].a, b = e[i].b, w = e[i].w; + int a = edge[i].a, b = edge[i].b, c = edge[i].c; a = find(a), b = find(b); if (a != b) - p[a] = b, res += w; + p[a] = b, res += c; } return res; } int main() { cin >> n; + // 建立超级源点(0 <-> 1~n ) - int w; + int c; for (int i = 1; i <= n; i++) { - cin >> w; // 点权 - e[el++] = {0, i, w}; - e[el++] = {i, 0, w}; + cin >> c; // 点权转边权 + edge[el++] = {0, i, c}; + edge[el++] = {i, 0, c}; } // 本题是按矩阵读入的,不是按a,b,c方式读入的 for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) { - cin >> w; - e[el++] = {i, j, w}; - e[el++] = {j, i, w}; + cin >> c; + edge[el++] = {i, j, c}; + edge[el++] = {j, i, c}; } // 利用Kruskal计算最小生成树 - printf("%d\n", kruskal()); + cout << kruskal() << endl; return 0; } @@ -131,34 +133,36 @@ const int N = 310; int n; int g[N][N]; -int dist[N]; +int dis[N]; bool st[N]; int res; // 最小生成树里面边的长度之和 -int prim() { - memset(dist, 0x3f, sizeof dist); // 初始化所有距离为INF - dist[0] = 0; // 超级源点是在生成树中的 +void prim() { + memset(dis, 0x3f, sizeof dis); // 初始化所有距离为INF + dis[0] = 0; // 超级源点是在生成树中的 for (int i = 0; i <= n; i++) { // 注意:这里因为引入了超级源点,所以点的个数是n+1 int t = -1; for (int j = 0; j <= n; j++) - if (!st[j] && (t == -1 || dist[t] > dist[j])) - t = j; - st[t] = true; - res += dist[t]; + if (!st[j] && (t == -1 || dis[t] > dis[j])) t = j; + + if (i) res += dis[t]; // 有超级源点的题,是必然存在最小生成树的 // 注意这里也是需要从0~n共n+1个 - for (int j = 0; j <= n; j++) dist[j] = min(dist[j], g[t][j]); + for (int j = 0; j <= n; j++) + if (!st[j] && dis[j] > g[t][j]) + dis[j] = g[t][j]; + st[t] = true; } - return res; } int main() { cin >> n; // 建立超级源点(0 <-> 1~n ),点权转化为超级源点到此节点的边权 for (int i = 1; i <= n; i++) { - cin >> g[0][i]; - g[i][0] = g[0][i]; + int c; + cin >> c; + g[i][0] = g[0][i] = c; } // 本题是按矩阵读入的,不是按a,b,c方式读入的 for (int i = 1; i <= n; i++) @@ -166,7 +170,8 @@ int main() { cin >> g[i][j]; // 利用prim计算最小生成树 - printf("%d\n", prim()); + prim(); + cout << res << endl; return 0; } diff --git a/TangDou/AcWing/MinimalSpanningTree/1146_Kruskal.cpp b/TangDou/AcWing/MinimalSpanningTree/1146_Kruskal.cpp index 8137991..f95b190 100644 --- a/TangDou/AcWing/MinimalSpanningTree/1146_Kruskal.cpp +++ b/TangDou/AcWing/MinimalSpanningTree/1146_Kruskal.cpp @@ -1,18 +1,19 @@ #include using namespace std; const int N = 310; -const int INF = 0x3f3f3f3f; int n; // n条顶点 int res; // 最小生成树的权值和 -int el; // 边数 + // Kruskal用到的结构体 const int M = 2 * N * N; // 无向图*2,稠密图N*N struct Edge { - int a, b, w; + int a, b, c; const bool operator<(const Edge &t) const { - return w < t.w; + return c < t.c; } -} e[M]; +} edge[M]; +int el; // 边数 + // 并查集 int p[N]; int find(int x) { @@ -22,39 +23,40 @@ int find(int x) { // Kruskal算法 int kruskal() { // 按边的权重排序 - sort(e, e + el); + sort(edge, edge + el); // 初始化并查集,注意并查集的初始是从0开始的,因为0号是超级源点 for (int i = 0; i <= n; i++) p[i] = i; // 枚举每条边 for (int i = 0; i < el; i++) { - int a = e[i].a, b = e[i].b, w = e[i].w; + int a = edge[i].a, b = edge[i].b, c = edge[i].c; a = find(a), b = find(b); if (a != b) - p[a] = b, res += w; + p[a] = b, res += c; } return res; } int main() { cin >> n; + // 建立超级源点(0 <-> 1~n ) - int w; + int c; for (int i = 1; i <= n; i++) { - cin >> w; // 点权 - e[el++] = {0, i, w}; - e[el++] = {i, 0, w}; + cin >> c; // 点权转边权 + edge[el++] = {0, i, c}; + edge[el++] = {i, 0, c}; } // 本题是按矩阵读入的,不是按a,b,c方式读入的 for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) { - cin >> w; - e[el++] = {i, j, w}; - e[el++] = {j, i, w}; + cin >> c; + edge[el++] = {i, j, c}; + edge[el++] = {j, i, c}; } // 利用Kruskal计算最小生成树 - printf("%d\n", kruskal()); + cout << kruskal() << endl; return 0; } \ No newline at end of file diff --git a/TangDou/AcWing/MinimalSpanningTree/1146_Prim.cpp b/TangDou/AcWing/MinimalSpanningTree/1146_Prim.cpp index 7d66eb3..910a52b 100644 --- a/TangDou/AcWing/MinimalSpanningTree/1146_Prim.cpp +++ b/TangDou/AcWing/MinimalSpanningTree/1146_Prim.cpp @@ -5,34 +5,36 @@ const int N = 310; int n; int g[N][N]; -int dist[N]; +int dis[N]; bool st[N]; int res; // 最小生成树里面边的长度之和 -int prim() { - memset(dist, 0x3f, sizeof dist); // 初始化所有距离为INF - dist[0] = 0; // 超级源点是在生成树中的 +void prim() { + memset(dis, 0x3f, sizeof dis); // 初始化所有距离为INF + dis[0] = 0; // 超级源点是在生成树中的 for (int i = 0; i <= n; i++) { // 注意:这里因为引入了超级源点,所以点的个数是n+1 int t = -1; for (int j = 0; j <= n; j++) - if (!st[j] && (t == -1 || dist[t] > dist[j])) - t = j; - st[t] = true; - res += dist[t]; + if (!st[j] && (t == -1 || dis[t] > dis[j])) t = j; + + if (i) res += dis[t]; // 有超级源点的题,是必然存在最小生成树的 // 注意这里也是需要从0~n共n+1个 - for (int j = 0; j <= n; j++) dist[j] = min(dist[j], g[t][j]); + for (int j = 0; j <= n; j++) + if (!st[j] && dis[j] > g[t][j]) + dis[j] = g[t][j]; + st[t] = true; } - return res; } int main() { cin >> n; // 建立超级源点(0 <-> 1~n ),点权转化为超级源点到此节点的边权 for (int i = 1; i <= n; i++) { - cin >> g[0][i]; - g[i][0] = g[0][i]; + int c; + cin >> c; + g[i][0] = g[0][i] = c; } // 本题是按矩阵读入的,不是按a,b,c方式读入的 for (int i = 1; i <= n; i++) @@ -40,7 +42,8 @@ int main() { cin >> g[i][j]; // 利用prim计算最小生成树 - printf("%d\n", prim()); + prim(); + cout << res << endl; return 0; } \ No newline at end of file