首页 > 代码库 > 3366 【模板】最小生成树(Prim)

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

3366 【模板】最小生成树(Prim)