图论 - 无向图最小生成树
N个点M条边的无向连通图,每条边有一个权值,求该图的最小生成树。
Input
第1行:2个数N,M中间用空格分隔,N为点的数量,M为边的数量。(2 <= N <= 1000, 1 <= M <= 50000)
第2 - M + 1行:每行3个数S E W,分别表示M条边的2个顶点及权值。(1 <= S, E <= N,1 <= W <= 10000)
Output
输出最小生成树的所有边的权值之和。
Input示例
9 14
1 2 4
2 3 8
3 4 7
4 5 9
5 6 10
6 7 2
7 8 1
8 9 7
2 8 11
3 9 2
7 9 6
3 6 4
4 6 14
1 8 8
Output示例
37
---------------------------------------------------------------我是分割线^_^-----------------------------------------------------------
#include <iostream>
#include <cstdio>
#include <cstring> #include <cmath> #include <algorithm> using namespace std; const int INF = 0x3f3f3f3f; const int MAXN = 1005; const int MAXM = 50005; int cost[MAXN][MAXN]; struct Edge { int s, t, d; // s为起点,t为终点,d为权值 } edge[MAXM]; /** * prim算法 * @param cost: 赋权邻接矩阵 * @param n: 节点的编号,为1-n */ int prim(int cost[][MAXN], int n) { int rst = 0; bool vis[MAXN]; // 标记节点是否被加入 int label[MAXN]; // 选择节点的依据 memset(vis, false, sizeof(vis)); vis[1] = true; // 从任意一个节点开始 for (int i = 1; i <= n; ++i) { label[i] = cost[1][i]; } for (int times = 1; times <= n - 1; ++times) { // 循环n - 1次,每次加入一个节点 int minEdge = INF; int choosed = -1; for (int i = 1; i <= n; ++i) { //选择可扩张边上的节点 if (!vis[i] && label[i] < minEdge) { minEdge = label[i]; choosed = i; } } if (minEdge == INF) { // mincost没更新,说明原图没有联通 return -1; } rst += minEdge; vis[choosed] = true; for (int i = 1; i <= n; ++i) { // 更新节点的标记值 if (!vis[i] && cost[choosed][i] < label[i]) { label[i] = cost[choosed][i]; } } } return rst; } void addEdge(int id, int s, int t, int d) { edge[id].s = s; edge[id].t = t; edge[id].d = d; } bool cmp(Edge edge1, Edge