
|
| 4 |

|
| -1 |

Prim 算法和 朴素版的 Dijkstra 有点类似,也叫做 朴素版Prim算法,但也还是有点区别。
Dijkstra 中,只要起点到目的点的最短距离。
最小生成树,表示 不定某个起点和终点,要求遍历完所有点的 最短距离。
所以,朴素版的 Prim 和 朴素版的 Dijkstra 很相似。
区别在于更新 dist 的时候,Dijkstra 更新的是距离,Prim 更新的是 集合之间的最短边。
即
- for(int j = 0;j < n;++j)
- {
- dist[j] = min(dist[j],g[t][j]);
- }
最小生成树中,是 找 集合到集合之间的 最小边, Dijkstra最短距离是 节点之间的最小距离。
- #include
- #include
- #include
- #include
- #include
- #include
- #define endl '\n'
- #define YES puts("YES")
- #define NO puts("NO")
- #define INF 0x3f3f3f3f
- #define umap unordered_map
- #define All(x) x.begin(),x.end()
- #pragma GCC optimize(3,"Ofast","inline")
- #define IOS std::ios::sync_with_stdio(false),cin.tie(0), cout.tie(0)
- using namespace std;
- const int N = 500 + 10;
-
- int n,k;
-
- int g[N][N]; // 存储结点之间的最短边
- bool st[N]; // 标记是否遍历过该点
- int dist[N]; // 存储集合之间的最短边
-
- inline int Prim()
- {
- // 初始化集合之间的最短边方案为无穷
- memset(dist,INF,sizeof dist);
- dist[0] = 0; // 初始化检查起始点最短边方案为 0
-
- int ans = 0; // 存储最小生成树的最短边
-
- for(int i = 0;i < n;++i)
- {
- int t = -1; // 探头 t 探索每个结点,哪个是最短边
- for(int j = 0;j < n;++j)
- {
- // 如果符合 最短边结点,且为遍历过该结点 那么更新 t
- if(!st[j] && (t == -1 || dist[j] < dist[t]))t = j;
- }
-
- // 如果存在孤立点 那么肯定无法遍历完所有点,没有最小生成树返回 -1
- if(i && dist[t] >= INF) return -1;
-
- st[t] = true; // 标记好已经遍历了 该 t 结点
-
- if(i) ans += dist[t]; // 如果已经开始走动了,那么开始存储集合之间的最短边
-
- for(int j = 0;j < n;++j) dist[j] = min(dist[j],g[t][j]); // 更新所有最短边,即 t 点到 j 点之间的最短边
- }
- if(ans >= INF) return -1; // 如果存在孤立点,返回 -1
- return ans; // 返回最小生成树最短边
- }
-
- inline void solve()
- {
- // 初始化集合之间的边长为无穷
- memset(g,INF,sizeof g);
-
- cin >> n >> k;
- while(k--)
- {
- int a,b,c;
- cin >> a >> b >> c;
- // 存储结点之间最短边
- g[a][b] = g[b][a] = min(g[a][b],c);
- }
- cout << Prim() << endl;
- }
-
- int main()
- {
- // freopen("a.txt", "r", stdin);
- IOS;
- int _t = 1;
- // cin >> _t;
- while (_t--)
- {
- solve();
- }
-
- return 0;
- }
