## [$AcWing$ $1140$. 最短网络](https://www.acwing.com/problem/content/1142/) ### 一、题目描述 农夫约翰被选为他们镇的镇长! 他其中一个竞选承诺就是在镇上建立起互联网,并连接到所有的农场。 约翰已经给他的农场安排了一条高速的网络线路,他想把这条线路共享给其他农场。 约翰的农场的编号是$1$,其他农场的编号是 $2$∼$n$。 为了使花费最少,他希望用于连接所有的农场的 **光纤总长度尽可能短**。 你将得到一份各农场之间连接距离的列表,你必须找出能连接所有农场并使所用光纤最短的方案。 **输入格式** 第一行包含一个整数 $n$,表示农场个数。 接下来 $n$ 行,每行包含 $n$ 个整数,输入一个对角线上全是$0$的对称矩阵。 其中第 $x+1$ 行 $y$ 列的整数表示连接农场 $x$ 和农场 $y$ 所需要的光纤长度。 **输出格式** 输出一个整数,表示所需的最小光纤长度。 **数据范围** $3≤n≤100$ 每两个农场间的距离均是非负整数且不超过$100000$。 **输入样例** ```c++ 4 0 4 9 21 4 0 8 17 9 8 0 16 21 17 16 0 ``` **输出样例** ```c++ 28 ``` ### 三、$Prim$ 算法 ```cpp {.line-numbers} #include using namespace std; const int N = 110; const int INF = 0x3f3f3f3f; int n; int g[N][N]; int dis[N]; bool st[N]; int res; int prim() { memset(dis, 0x3f, sizeof dis); dis[1] = 0; for (int i = 0; i < n; i++) { // 迭代n次 int t = -1; for (int j = 1; j <= n; j++) if (!st[j] && (t == -1 || dis[t] > dis[j])) t = j; if (i && dis[t] == INF) return INF; // 非连通图,没有最小生成树 if (i) res += dis[t]; for (int j = 1; j <= n; j++) if (!st[j] && g[t][j] < dis[j]) { dis[j] = g[t][j]; } st[t] = true; } return res; } int main() { cin >> n; // 初始化 memset(g, 0x3f, sizeof g); for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) cin >> g[i][j]; // 有向图 cout << prim() << endl; return 0; } ``` ### 四、$kruscal$ 算法 ```cpp {.line-numbers} #include using namespace std; const int N = 110, M = 10010; const int INF = 0x3f3f3f3f; int n, m; // n个节点,m条边 // Kruskal用到的结构体 struct Node { int a, b, c; bool const operator<(const Node &t) const { return c < t.c; // 边权小的在前 } } edge[M]; // 数组长度为是边数 // 并查集 int p[N]; int find(int x) { if (p[x] != x) p[x] = find(p[x]); return p[x]; } int res; // 最小生成树的权值和 int cnt; // 最小生成树的结点数 // Kruskal算法 void kruskal() { // 1、按边权由小到大排序 sort(edge, edge + m); // 2、并查集初始化 for (int i = 1; i <= n; i++) p[i] = i; // 3、迭代m次 for (int i = 0; i < m; i++) { 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 += c, cnt++; // cnt是指已经连接上边的数量 } // 4、特判是不是不连通 if (cnt < n - 1) res = INF; } int main() { cin >> n; // 邻接矩阵 for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) { int c; cin >> c; edge[m++] = {i, j, c}; // 加入当前的边 } kruskal(); cout << res << endl; return 0; } ```