码迷,mamicode.com
首页 > 编程语言 > 详细

最小生成树之算法记录【prime算法+Kruskal算法】

时间:2015-07-23 21:29:52      阅读:216      评论:0      收藏:0      [点我收藏+]

标签:

首先说一下什么是树:

    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;
}

 用一个题来实现上述两个算法:

省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。经过调查评估,得到的统计表中列出了有可能建设公路的若干条道路的成本。现请你编写程序,计算出全省畅通需要的最低成本。
 
Input
测试输入包含若干测试用例。每个测试用例的第1行给出评估的道路条数 N、村庄数目M ( < 100 );随后的 N
行对应村庄间道路的成本,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间道路的成本(也是正整数)。为简单起见,村庄从1到M编号。当N为0时,全部输入结束,相应的结果不要输出。
 
Output
对每个测试用例,在1行里输出全省畅通需要的最低成本。若统计数据不足以保证畅通,则输出“?”。
 
Sample Input
3 3
1 2 1
1 3 2
2 3
4 1 3
2 3 2
0 100
 
Sample Output
3
?

 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; 
} 

 

最小生成树之算法记录【prime算法+Kruskal算法】

标签:

原文地址:http://www.cnblogs.com/tonghao/p/4671746.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!