最小生成树
普里姆算法:
有n个顶点,每两个顶点之间都有权值;
从顶点v0 开始构造最小生成树T。
low数组记录已经构成树的顶点和未构成树的顶点之间的边的权值。
循环n-1次
{
找到low数组里面最小的权值的边,并加入构成树的顶点数组中。
更新low数组内边的权值。
}
代码:
#include <stdio.h> #include <iostream> #include <cstring> using namespace std; #define MaxInt 0xfffffff #define N 105 int map[N][N],low[N]; //map记录节点间的权值 low记录当前选中点与未选中点的权值 bool v[N]; //标记数组 int n; int prim() { int i, j, pos, min, sum=0; //记录最小生成树权值之和 pos=1; //记录新加入的点的下标 v[1] = 1; for(i=1; i<=n; i++) //更新low数组 if(i!=pos) low[i] = map[pos][i]; for(i=1; i<n; i++) { min = MaxInt; for(j=1; j<=n; j++) if(!v[j] && low[j]<min)//找到最小的边,记录其顶点 { min = low[j]; pos = j; } sum += min; v[pos]= 1; for(j=1; j<=n; j++) if(!v[j] && low[j]>map[pos][j]) //更新low数组内的权值 low[j] = map[pos][j]; } return sum; } int main() { int i, j; while(scanf("%d",&n)!=EOF) { for(i=1; i<=n; i++) for(j=1; j<=n; j++) scanf("%d", &map[i][j]); memset(v, 0, sizeof(v)); printf("%d\n",prim()); } return 0; }
克鲁卡斯算法:
自我理解:
就是运用并查集。
先将所有的边排序,从最小的开始查找。
每条边都有两个顶点,如果两个顶点不是在同一个集合,则进行并查集合并。
所有的边合并成同一个集合时,最小生成树也就构成(因为每次都是合并的都是当前最短的边)。
代码:
#include <stdio.h> #include <iostream> #include <cstring> #include <algorithm> using namespace std; #define MaxInt 0xfffffff #define N 105 struct node { int i, j; int low; } map[5000]; int v[N]; //并查集数组 int n, k; //n顶点数 k边数 bool cmp(const node &a, const node &b) //排序(小—>大) { return a.low<b.low; } int find(int t) //并查集的找根 { while(v[t]!=t) t=v[t]; return t; } int S() { int sum=0, i; sort(map, map+k, cmp); //对每条边按照权值大小排序(小的在前) for(i=1; i<=n; i++) //并查集初始化 v[i]=i; for(i=0; i<k; i++) //从权值最小的边开始 { int v1=map[i].i; //边的顶点 int v2=map[i].j; int s1=find(v1); //看两个顶点是否已经属于一个集合 int s2=find(v2); if(s1!=s2) { sum += map[i].low; v[s1]=s2; } } return sum; } int main() { int i, j, a; while(scanf("%d",&n)!=EOF) { for(k=0, i=1; i<=n; i++) for(j=1; j<=n; j++) { scanf("%d", &a); if(i<j) { map[k].i=i; map[k].j=j; map[k++].low=a; } } memset(v, 0, sizeof(v)); printf("%d\n", S()); } return 0; }

浙公网安备 33010602011771号