标签:
首先说一下什么是树:
1、只含一个根节点
2、任意两个节点之间只能有一条或者没有线相连
3、任意两个节点之间都可以通过别的节点间接相连
4、除了根节点没一个节点都只有唯一的一个父节点
最小生成树就是:
在所有数据满足是一棵树的情况下一条将所有节点都连接起来且长度最短的一条路(因为任意两个节点之间有权值
(相连的两点之间权值为一个具体的数,不相连的两个点之间权值为无穷大))
下面介绍通用的求最小生成树的两种算法:
(1)prime算法:
/* * 数组tree[]用来记录最小生成树的节点 * 数组lowdis[]记录从起点到其余所有点的距离并不断更新 * 数组map[][]记录所有数据两点之间的距离 * point是所有节点的数目,begin是起点 * mindis是最小生成树的长度 */ void prime() { int i,j,min,mindis=0,next; memset(tree,0,sizeof(tree)); for(i=1;i<=point;i++) { lowdis[i]=map[begin][i];//用lowdis[]数组记录下从起点到剩下所有点的距离 } tree[begin]=1;//标记起点(即最小生成树中的点) for(i=1;i<point;i++) { min=INF; for(j=1;j<=point;j++) { if(!tree[j]&&min>lowdis[j]) { min=lowdis[j];//求出从当前起点到其余所有点的距离中最短的 next=j; } } mindis+=min;//记录下整条最小树的长度 tree[next]=1; for(j=1;j<=point;j++) { if(!tree[j]&&lowdis[j]>map[next][j]) lowdis[j]=map[next][j];//更新lowdis[]数组 } } printf("%d\n",mindis); }
kruskal算法:
此算法的核心就是在并查集(并查集知识请看 知识小总结记录分类中的并查集)的基础上对两点之间距离进行排序:
find()函数用来查找根节点
int find(int father)//查找根节点 { int t; int children=father; while(father!=set[father]) father=set[father]; while(fa!=set[children]) { t=set[children]; set[children]=fa; children=t; } return father; }
mix函数用来合并两个节点,使两个节点的父节点相同
void mix(int x,int y)//将两个点合并(即另两点根节点相同) { int fx; int fy; fx=find(x); fy=find(y); if(fx!=fy) set[fx]=fy; }
用一个题来实现上述两个算法:
prime算法:
#include<stdio.h> #include<string.h> #define INF 0x3f3f3f int lowcost[110];//此数组用来记录第j个节点到其余节点最少花费 int map[110][110];//用来记录第i个节点到其余n-1个节点的距离 int visit[110];//用来记录最小生成树中的节点 int city; void prime() { int min,i,j,next,mincost=0; memset(visit,0,sizeof(visit));//给最小生成树数组清零 for(i=1;i<=city;i++) { lowcost[i]=map[1][i];//初始化lowcost数组为第1个节点到剩下所有节点的距离 } visit[1]=1;//选择第一个点为最小生成树的起点 for(i=1;i<city;i++) { min=INF; for(j=1;j<=city;j++) { if(!visit[j]&&min>lowcost[j])//如果第j个点不是最小生成树中的点并且其花费小于min { min=lowcost[j]; next=j;//记录下此时最小的位置节点 } } if(min==INF) { printf("?\n"); return ; } mincost+=min;//将最小生成树中所有权值相加 visit[next]=1;//next点加入最小生成树 for(j=1;j<=city;j++) { if(!visit[j]&&lowcost[j]>map[next][j])//如果第j点不是最小生成树中的点并且此点处权值大于第next点到j点的权值 { lowcost[j]=map[next][j]; //更新lowcost数组 } } } printf("%d\n",mincost); } int main() { int road; int j,i,x,y,c; while(scanf("%d%d",&road,&city)&&road!=0) { memset(map,INF,sizeof(map));//初始化数组map为无穷大 while(road--) { scanf("%d%d%d",&x,&y,&c); map[x][y]=map[y][x]=c;//城市x到y的花费==城市y到想的花费 } prime(); } return 0; }
kruskal算法:
#include<stdio.h> #include<algorithm> using namespace std; int set[110]; struct record { int beg; int end; int money; }s[11000]; int find(int fa) { int ch=fa; int t; while(fa!=set[fa]) fa=set[fa]; while(ch!=fa) { t=set[ch]; set[ch]=fa; ch=t; } return fa; } void mix(int x,int y) { int fx,fy; fx=find(x); fy=find(y); if(fx!=fy) set[fx]=fy; } bool cmp(record a,record b) { return a.money<b.money; } int main() { int city,road,n,m,j,i,sum; while(scanf("%d",&road)&&road!=0) { scanf("%d",&city); for(i=0;i<road;i++) { scanf("%d%d%d",&s[i].beg,&s[i].end,&s[i].money); } for(i=1;i<=city;i++) set[i]=i; sort(s,s+road,cmp); sum=0; for(i=0;i<road;i++) { if(find(s[i].beg)!=find(s[i].end)) { mix(s[i].beg,s[i].end); sum+=s[i].money; } } j=0; for(i=1;i<=city;i++) { if(set[i]==i) j++; if(j>1) break; } if(j>1) printf("?\n"); else printf("%d\n",sum); } return 0; }
标签:
原文地址:http://www.cnblogs.com/tonghao/p/4671746.html