3366 【模板】最小生成树(Prim)
题目描述
如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出orz
输入输出格式
输入格式:
第一行包含两个整数N、M,表示该图共有N个结点和M条无向边。(N<=5000,M<=200000)
接下来M行每行包含三个整数Xi、Yi、Zi,表示有一条长度为Zi的无向边连接结点Xi、Yi
输出格式:
输出包含一个数,即最小生成树的各边的长度之和;如果该图不连通则输出orz
代码:
1 #include<iostream> 2 #include<vector> 3 #include<queue> 4 #include<algorithm> 5 using namespace std; 6 const int inf = 1<<30; 7 int n, m; 8 struct edge{ 9 int k, w; 10 }; 11 bool operator<(const edge&e1, const edge&e2){ 12 return e1.w > e2.w; 13 } 14 priority_queue<edge>pq; 15 vector<vector<edge> >v; 16 int d[5010]; 17 bool used[5010]; 18 19 int main(){ 20 cin>>n>>m; 21 int i; 22 int donenum = 0; 23 v.clear(); 24 v.resize(n+1); 25 edge p, p2; 26 for(i = 1; i <= m; i++){ 27 int a, b, c; 28 cin>>a>>b>>c; 29 p.k = b; 30 p.w = c; 31 v[a].push_back(p); 32 p2.k = a; 33 p2.w = c; 34 v[b].push_back(p2); 35 } 36 for(i = 1; i <= n; i++) d[i] = inf; 37 p.k = 1; 38 p.w = 0; 39 int way = 0; 40 pq.push(p); 41 while(!pq.empty()&&donenum<n){ 42 p = pq.top(); 43 pq.pop(); 44 if(used[p.k]) continue; 45 way += p.w; donenum++; 46 used[p.k] = true; 47 for(i = 0; i < v[p.k].size(); i++){ 48 edge q; 49 q.k = v[p.k][i].k; 50 if(used[q.k]) continue; 51 q.w = v[p.k][i].w; 52 pq.push(q); 53 } 54 } 55 if(donenum<n) cout<<"orz"; 56 else cout<<way; 57 return 0; 58 }
备注:
借着刚默写完一遍dijkstra的劲头,把Prim过了一遍。Prim跟dijkstra神似嘛,所以就想怎么把dijkstra改成Prim。因为gw的ppt上Prim的写法和dijkstra还是有些区别的。。
两个算法很小的区别已在代码中标出。最开始我特别nc,以为在pop后把p.w的值加起来就行了,实际上,p.w是每个点到源点的距离,而不是到最小生成树的距离,所以当然不能这么加。
要改的关键就是要记录下来每个点到最小生成树的距离,而不是到源点的距离。所以实际上只要改标黄那三行就可以了!ps:我是写着写着才突然发现实际上就是把dijkstra的q.w = p.w + v[p.k][i].w改成q.w = v[p.k][i].w就行了。
看来对dijkstra的深刻理解还是很有价值的。hhh