Prim算法的3个版本
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Prim算法的3个版本相关的知识,希望对你有一定的参考价值。
Prim:以贪心的思想求得最小生成树: 把已建成的树看成一个结点, 然后用贪心的方法每次添加距离最短的点。
以Poj1258为例:http://poj.org/problem?id=1258
1.朴素版本:邻接矩阵, 无任何优化, O(n^2)
1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstring> 5 #include <algorithm> 6 #include <cmath> 7 using namespace std; 8 9 const int maxn = 100 + 2; 10 int map[maxn][maxn]; 11 bool vis[maxn]; 12 int dist[maxn]; 13 int n; 14 15 int Prim(int x) 16 { 17 int ret = 0, p = 0; 18 vis[x] = true; 19 dist[x] = 0; 20 21 for(int i = 1; i < n; i++) 22 { 23 for(int r = 1; r <= n; r++) 24 if(map[x][r]) 25 dist[r] = min(dist[r], map[x][r]); 26 27 for(int r = 1; r <= n; r++) 28 if(!vis[r]) 29 p = p ? (dist[p] < dist[r] ? p : r) : r; 30 31 ret += dist[p]; 32 x = p, p = 0; 33 vis[x] = true; 34 } 35 return ret; 36 } 37 38 int main() 39 { 40 //freopen("in.txt", "r", stdin); 41 42 while(~scanf("%d", &n)) 43 { 44 for(int i = 1; i <= n; i++) 45 for(int r = 1; r <= n; r++) 46 scanf("%d", &map[i][r]); 47 48 memset(vis, false, sizeof(vis)); 49 memset(dist, 0x7f, sizeof(dist)); 50 51 printf("%d\n", Prim(1)); 52 } 53 }
也没什么可解释的.
2.临界矩阵, 优先队列优化(堆同), O(nlogn)
1 #include <iostream> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cstdio> 5 #include <algorithm> 6 #include <cmath> 7 #include <queue> 8 using namespace std; 9 10 const int maxn = 100 + 2; 11 priority_queue< pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > q; 12 int map[maxn][maxn]; 13 bool vis[maxn]; 14 int dist[maxn]; 15 int n; 16 17 int Prim(int x) 18 { 19 memset(vis, false, sizeof(vis)); 20 memset(dist, 0x7f, sizeof(dist)); 21 int ret = 0; 22 dist[x] = 0; 23 24 while(!q.empty()) q.pop(); 25 26 for(int i = 1; i < n; i++) 27 { 28 vis[x] = true; 29 30 for(int r = 1; r <= n; r++) 31 if(dist[r] > map[x][r] && map[x][r] && !vis[r]) 32 dist[r] = map[x][r], q.push(make_pair(dist[r], r)); 33 34 while(!q.empty() && vis[q.top().second]) 35 q.pop(); 36 37 x = q.top().second; 38 ret += dist[x]; 39 } 40 return ret; 41 } 42 43 int main() 44 { 45 // freopen("in.txt", "r", stdin); 46 47 while(~scanf("%d", &n)) 48 { 49 for(int i = 1; i <= n; i++) 50 for(int r = 1; r <= n; r++) 51 scanf("%d", &map[i][r]); 52 53 printf("%d\n", Prim(1)); 54 } 55 56 57 }
<1>.pair<typename, pytename> p:是一种结构体,只有两个元素,<, >两个typename 分别为两个元素的类型
通过 p.first, p.second 分别访问第一个元素和第二个元素。
<2>.memset(name, value, sizeof), 属于 string.h 是字符数组的填充函数, 因为字符char类型为1字节,所以填充int数组时也是按单字节填充, 初始化时若每个字节的值过大, 会出现负数(整数存储原理, 补码。)
<3> priority_queue< pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > q;为声明小根堆(个人感觉优先队列和堆区分不用很明显, 因为内部存储结构已经不重要), 相邻的两个相同左右尖括号要用空格隔开, 否则会组成左移右移运算符, 此程序中时对pair进行排序, 在排序时以第一个元素为关键字, 所以pair.first应该存dist, 而不是点的编号。
<4>.补充一下。priority_queue< pair<int, int> > q; 为声明大根堆
3.邻接表, 优先队列
1 #include <iostream> 2 #include <cstdlib> 3 #include <cstdio> 4 #include <cstring> 5 #include <queue> 6 using namespace std; 7 8 const int maxn = 10000 + 2, maxm = 100000 + 2; 9 #define pii pair<int, int> 10 #define fi first 11 #define se second 12 #define MP make_pair 13 14 priority_queue<pii, vector<pii >, greater<pii > > heap; 15 int n, m, dist[maxn], s, t; 16 bool vis[maxn]; 17 18 struct arc 19 { 20 int e, v; 21 arc *next; 22 arc(){} 23 arc(int e, int v, arc *next) : e(e), v(v), next(next){} 24 void *operator new(unsigned, void *p) {return p;} 25 }*head[maxn], mem[maxm * 2], *sp = mem; 26 27 inline void addarc(int x, int y, int v) 28 { 29 head[x] = new(sp++) arc(y, v, head[x]); 30 head[y] = new(sp++) arc(x, v, head[y]); 31 } 32 33 int Prim(int x) 34 { 35 memset(dist, 0x7f, sizeof(dist)); 36 dist[x] = 0; 37 int ans = 0; 38 for (int i = 1; i < n; i++) 39 { 40 vis[x] = true; 41 for (arc *p = head[x]; p; p = p -> next) 42 if (dist[p -> e] > p -> v) 43 dist[p -> e] = p -> v, heap.push(MP(dist[p -> e], p -> e)); 44 45 while (!heap.empty() && vis[heap.top().se]) heap.pop(); 46 47 x = heap.top().se; 48 ans += dist[x]; 49 } 50 return ans; 51 } 52 53 int main() 54 { 55 freopen("Prim.in", "r", stdin); 56 freopen("Prim.out", "w", stdout); 57 58 scanf("%d%d", &n, &m); 59 int a, b, c; 60 for (int i = 1; i <= m; i++) 61 scanf("%d%d%d", &a, &b, &c), addarc(a, b, c); 62 63 printf("%d\n", Prim(1)); 64 65 return fclose(stdin), fclose(stdout), 0; 66 }
1.前向星存储图,一种牺牲空间获取时间的方法,在算法竞赛中的试用比较普遍的做法。
2.没什么好解释的了...
以上是关于Prim算法的3个版本的主要内容,如果未能解决你的问题,请参考以下文章