~. 最近数据结构课讲到了prim算法,然而一直使用kruskal算法的我还不知prim的思想,实在是寝食难安,于此灯火通明之时写此随笔,以祭奠我睡过去的数
据结构课。
一,最小生成树之prim
prim的思路就是先任取一点(记为st)加入集合(数组s[]) ,然后在顶点集(数组v[]) 中 未被取的点集中(v - s) 选取一点记为en, 要求是:边 a[st][en]
是 a[i][j] (i 属于 s, j 属于 v-s) 中最小的,然后不断重复此过程(从v-s中选点加入s),直到 v-s 中只剩一个点。
关键点在于找a[i][j]中最小的。ok,来一个数组暂存(记为mi[]),比如说最开始 s[] 中只有一个点 1, 那么 mi[] 保存的就是 a[1][1],a[1][2]...a[1][n] ;
(等下再说a[][]赋值的细节),然后选取了一个点,假如是2吧!那就把2这个点标记一下(就是表明已经加入了,即:vis[2] = true;),然后更新 mi[]数组,
说明一下,mi[]保存的是 集合 s 中的点 i 到 v-s中的点 j 的最小距离 (指 mi [ j ] = min(a[i][j]) 其中 i 取遍 s )。这么多废话之后就可以上代码了~_~。
hdu 1102 (http://acm.hdu.edu.cn/showproblem.php?pid=1102)
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <iostream> 4 #include <algorithm> 5 #include <cstring> 6 #include <math.h> 7 using namespace std; 8 const int maxn = 110 ; 9 const int inf = 9999 ; 10 int a[maxn][maxn] , mi[maxn] ; 11 int N, M ; 12 bool vis[maxn] ; 13 14 int prim() 15 { 16 int ans = 0 , p , temp_min ; 17 vis[1] = true ; 18 for (int i = 1; i < N; i ++) { 19 temp_min = inf ; 20 for (int j = 1; j <= N; j ++) { 21 if (!vis[j] && temp_min > mi[j]) { 22 p = j ; 23 temp_min = mi[j] ; 24 } 25 } 26 ans += temp_min ; 27 vis[p] = true ; 28 for (int k = 1; k <= N; k ++) { 29 if (!vis[k] && a[p][k] < mi[k]) mi[k] = a[p][k] ; 30 } 31 } 32 return ans; 33 } 34 35 void sol() 36 { 37 for (int i = 1; i <= N; i ++) { 38 for (int j = 1; j <= N; j ++) { 39 scanf("%d",&a[i][j]) ; 40 if (i == 1) mi[j] = a[i][j] ; 41 } 42 } 43 memset(vis,false,sizeof(vis)) ; 44 cin >> M ; 45 int x, y ; 46 for (int i = 1; i <= M; i ++) { 47 scanf("%d%d",&x,&y) ; 48 a[x][y] = a[y][x] = 0 ; 49 if (x == 1) mi[y] = 0 ; 50 if (y == 1) mi[x] = 0 ; 51 } 52 mi[1] = 0 ; 53 cout << prim() << endl ; 54 } 55 56 int main() 57 { 58 while (cin >> N) { 59 sol() ; 60 } 61 return 0; 62 }
二,最小生成树之kruskal
kruskal的思路呢就是先把边给排个序,然后选啊选啊,当然是先选小的啦!至于为什么?呵呵哒!此处显露了并查集的~~~~超级~武器。
存储是有一个边集结构体,st (起点), en (终点) ,di(距离)。排序依据就是 di;如果选择的边的起点重点已经连在一起了,那在他们之间连一条边就是多余的 。
hdu 1102
1 #include <iostream> 2 #include <cstring> 3 #include <algorithm> 4 #include <cmath> 5 #include <stdio.h> 6 using namespace std; 7 const int maxn = 110 ; 8 const int inf = 9999999 ; 9 10 int s[maxn] ; 11 int ans ; 12 int f[maxn][maxn] ; 13 struct Node 14 { 15 int st ; 16 int en ; 17 int di ; 18 }; 19 20 Node A[5000] ; 21 bool cmp(const Node &T_1,const Node &T_2) 22 { 23 return T_1.di < T_2.di ; 24 } 25 26 int fi(int x) 27 { 28 int r = x, p = x, q ; 29 while (r != s[r]) { 30 r = s[r] ; 31 } 32 while (p != s[p]) { 33 q = s[p] ; 34 s[p] = r ; 35 p = q ; 36 } 37 return r ; 38 } 39 40 void join(int x,int y) 41 { 42 int fx = fi(x), fy = fi(y) ; 43 if (fx != fy) { 44 s[fx] = fy ; 45 } 46 } 47 48 int main() 49 { 50 int N, M, a, b, d , x; 51 while (cin >> N) { 52 for (int i = 1; i <= N; i++) { 53 s[i] = i ; 54 } 55 56 for (int i = 1; i <= N; i++) { 57 for (int j = 1; j <= N; j++) { 58 scanf("%d",&x) ; 59 f[i][j] = x ; 60 } 61 } 62 63 int k = 0 ; 64 for (int i = 1; i < N; i++) { 65 for (int j = i+1; j <= N; j++) { 66 A[k].st = i; 67 A[k].en = j ; 68 A[k].di = f[i][j] ; 69 k ++ ; 70 } 71 } 72 int n = N*(N-1)/2 ; 73 scanf("%d",&M) ; 74 for (int i = 1; i <= M; i++) { 75 scanf("%d %d",&a,&b) ; 76 join(a,b) ; 77 } 78 sort(A,A+n,cmp) ; 79 ans = 0; 80 for (int i = 0; i < n; i++) { 81 if (fi(A[i].st) != fi(A[i].en)) { 82 ans += A[i].di ; 83 join(A[i].st,A[i].en) ; 84 } 85 } 86 cout << ans << endl; 87 } 88 return 0 ; 89 }
三,至于上面两种方法的证明以及其他方法以后再写,小弟今晚要早睡了。