最小生成树:从图中选出一些边,构成一个树,包含图中所有点,且边的权值之和最小。
Kruskal
按边权对边排序,逐一检查,如果边的两点未联通,则采纳,否则跳过。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| struct MSTree{ private: struct Edge{ ll u,v,w; bool operator>(const Edge &e) const{ return w > e.w; } }; ll n; DSU dsu; priority_queue<Edge,vector<Edge>,greater<Edge>> Q; public: ll ans=0; vector<vector<pll>> G; vector<ll> fa; MSTree(ll _n):n(_n),dsu(_n),G(_n+1),fa(n+1,0){} void add_edge(ll u,ll v,ll w){ Q.push({u,v,w}); } void solve(){ ans = 0; while(!Q.empty()){ auto e = Q.top();Q.pop(); if(dsu.find(e.u) != dsu.find(e.v)){ dsu.merge(e.u,e.v); G[e.u].emplace_back(e.v,e.w); G[e.v].emplace_back(e.u,e.w); ans += e.w; } } auto DFS = [&](auto &&self, ll u=1,ll f=0) -> void{ fa[u] = f; for(auto &p:G[u]){ ll v = p.first; if(v == f) continue; self(self,v,u); } }; DFS(DFS); } bool connected(){ return dsu.size[dsu.find(1)] == n; } }; void solve(){ ll n,m;cin >> n >> m; MSTree mst(n); ll u,v,w; FORLL(i,1,m){ cin >> u >> v >> w; mst.add_edge(u,v,w); } mst.solve(); if(mst.connected()) cout << mst.ans << endl; else cout << "orz\n"; }
|
Prim
从一个结点开始,加入边权最小的e(u,v)
,其中u
在已选集合中,v
在未选集合中,直到所有点都被选。
实现略