constint N = 510; int n, m; int g[N][N], dist[N]; bitset<N> st;
voidprim(){ memset(dist, 0x3f, sizeof dist); dist[1] = 0; int res = 0; // 这里要循环 n 次而不是 m 次 // 才能保证循环到每个节点 for (int i = 0; i < n; i++) { // 找出当前未访问过的距离已经建成的集合距离最短的点 int t = -1; for (int j = 1; j <= n; j++) if (!st[j] && (t == -1 || dist[j] < dist[t])) t = j; st[t] = 1; // 当前节点与已构建的集合之间没有边 if (dist[t] == 0x3f3f3f3f) { cout << "impossible"; return; } // t 是距集合最近的点 res += dist[t]; for (int j = 1; j <= n; j++) // 这里是 [t][j] 还是 [j][t] 无所谓 它们一定一样 dist[j] = min(dist[j], g[t][j]); } // 注意这里输出的是 res 不是 dist[n], dist[n] 表示的是第n个节点到集合的距离 cout << res << '\n'; }
intmain(){ cin >> n >> m; memset(g, 0x3f, sizeof g); while (m--) { int a, b, c; cin >> a >> b >> c; g[a][b] = g[b][a] = min(g[a][b], c); } prim(); return0; }
易错点:
没有把所有边初始成 0x3f3f3f3f。
输入边时只设置了 a -> b 而没设置 b -> a。
没有取重边的最小值。
比较距离时是 min(dist[j], g[t][j]),而不是 dist[t] + g[t][j],因为它比较的是 j 这个元素到集合的距离,而 t 是刚选出来的对已建集合距离最小的点。
intmain(){ cin.tie(0), cout.tie(0), ios::sync_with_stdio(false); cin >> n >> m; for (int i = 1; i <= n; i++) p[i] = i; for (int i = 0; i < m; i++) cin >> edges[i].a >> edges[i].b >> edges[i].w;
// 排序数组 传入头指针和尾指针后一位 // 注意分清 m 和 n sort(edges, edges+m); int cnt = 0, res = 0; for (int i = 0; i < m; i++) { int a = edges[i].a, b = edges[i].b, w = edges[i].w; int pa = find(a), pb = find(b); if (pa != pb) { // 把 b 加到 a 里面(反过来也可以 无所谓) // 因为当前已经是有序的了 所以如果之前 b 已经在 a 中那么现在找到的这条边 // 就不是最短边 因此算法可以保证找到最小边 不需要去重 p[pb] = pa; cnt++; res += w; } } // n 个节点应该连 n-1 条边 if (cnt < n-1) cout << "impossible"; else cout << res; }