## [$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; int n; int g[N][N]; // 邻接矩阵,记录每两个点之间的距离 int dis[N]; // 每个点距离集合的最小长度 bool st[N]; // 是不是已经加入到集合中 int prim() { // 初始化所有节点到集合的距离为正无穷 memset(dis, 0x3f, sizeof dis); dis[1] = 0; // 1号节点到集合的距离为0 int res = 0; for (int i = 1; i <= n; i++) { // 迭代n次 int t = -1; //(1)是不是第一次 //(2)如果不是第1次那么找出距离最近的那个点j for (int j = 1; j <= n; j++) if (!st[j] && (t == -1 || dis[t] > dis[j])) // 第一次就是猴子选大王,赶鸭子上架 t = j; // 最小生成树的距离和增加dis[t] res += dis[t]; // t节点入集合 st[t] = true; // 利用t,拉近其它节点长度 for (int j = 1; j <= n; j++) dis[j] = min(dis[j], g[t][j]); } return res; } int main() { cin >> n; // 完全图,每两个点之间都有距离,不用考虑无解情况 for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) cin >> g[i][j]; // 利用prim算法计算最小生成树 cout << prim() << endl; return 0; } ``` ### 四、$kruscal$ 算法 ```cpp {.line-numbers} #include using namespace std; const int N = 110; const int M = 10010; struct Node { //用结构体存储每条边 int f, t, w; bool operator<(const Node &e) const { return w < e.w; } } edges[M]; int p[N]; int find(int x) { //并查集找根节点 if (p[x] != x) p[x] = find(p[x]); return p[x]; } int n, idx, ans; int main() { scanf("%d", &n); //邻接矩阵 for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) { int w; scanf("%d", &w); edges[idx++] = {i, j, w}; //加入当前的边 } sort(edges, edges + idx); //对边权进行排序,注意这里不是优先队列,是谁小谁在前 for (int i = 1; i <= n; i++) p[i] = i; //并查集初始化 for (int i = 1; i <= idx; i++) { //枚举每条边 int f = find(edges[i].f), t = find(edges[i].t); if (f != t) { //当前两点不连通 ans += edges[i].w; //更新答案 p[f] = t; //让两点变连通 } } printf("%d", ans); return 0; } ```