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

首先说一下什么是树:

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;
}
时间: 2024-07-28 18:31:23

最小生成树之算法记录【prime算法+Kruskal算法】的相关文章

最小生成树的两种算法:Prim和Kruskal算法

越来越明白了一个道理:你写不出代码的原因只有一个,那就是你没有彻底理解这个算法的思想!! 以前写过最小生成树,但是,水了几道题后,过了一段时间,就会忘却,一点也写不出来了.也许原因只有一个,那就是我没有彻底理解这两种算法. 主题: 其实,求最小生成树有两个要点,一个是权值最小,还有一个就是这个图必须是树.而Prim和Kruskal的不同之处在于两者选择的变量不同,Prim选择的是始终保持权值最小,然后逐个加点构建一棵树.而Kruskal则是始终保证是一棵树(虽然构建过程中不一定是真正的树,但并查

关于最小生成树(并查集)prime和kruskal

适合对并查集有一定理解的人.  新手可能看不懂吧.... 并查集简单点说就是将相关的2个数字联系起来 比如 房子                      1   2    3   4  5   6 能通向的房子        2   3    4  5  6    1 主要 建立并查集的 函数结构 模板(一般不变除非加权--最好能理解) for(int i=0;i<n;i++)         flag[i]=i;               //标记数组初始化以方便寻根 1 int find

poj 3625 Building Roads 最小生成树(prime或kruskal+并查集)(算法归纳)

Time Limit:1000MS Memory Limit:65536KB 64bit IO Format:%I64d & %I64u Description Farmer John had just acquired several new farms! He wants to connect the farms with roads so that he can travel from any farm to any other farm via a sequence of roads;

最小生成树-Prim算法和Kruskal算法

原文链接:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/30/2615542.html Prim算法 1.概览 普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树.意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (graph theory)),且其所有边的权值之和亦为最小.该算法于1930年由捷克数学家沃伊捷赫·亚尔尼克(英语:Vojtěch Jarník)发现:并在195

[转载]最小生成树-Prim算法和Kruskal算法

转载地址:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/30/2615542.html 自己在学,感觉这个讲的很不错,就转载了. Prim算法 1.概览 普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树.意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (graph theory)),且其所有边的权值之和亦为最小.该算法于1930年由捷克数学家沃伊捷赫·亚尔尼克(英语:Vo

最小生成树 Kruskal算法

Kruskal算法 1.概览 Kruskal算法是一种用来寻找最小生成树的算法,由Joseph Kruskal在1956年发表.用来解决同样问题的还有Prim算法和Boruvka算法等.三种算法都是贪婪算法的应用.和Boruvka算法不同的地方是,Kruskal算法在图中存在相同权值的边时也有效. 2.算法简单描述 1).记Graph中有v个顶点,e个边 2).新建图Graphnew,Graphnew中拥有原图中相同的e个顶点,但没有边 3).将原图Graph中所有e个边按权值从小到大排序 4)

转载:最小生成树-Prim算法和Kruskal算法

本文摘自:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/30/2615542.html 最小生成树-Prim算法和Kruskal算法 Prim算法 1.概览 普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树.意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (graph theory)),且其所有边的权值之和亦为最小.该算法于1930年由捷克数学家沃伊捷赫·亚尔尼克(英语:

Kruskal算法(贪心+并查集=最小生成树)

http://www.51nod.com/ Kruskal算法的高效实现需要一种称作并查集的结构.我们在这里不介绍并查集,只介绍Kruskal算法的基本思想和证明,实现留在以后讨论. Kruskal算法的过程: (1) 将全部边按照权值由小到大排序. (2) 按顺序(边权由小到大的顺序)考虑每条边,只要这条边和我们已经选择的边不构成圈,就保留这条边,否则放弃这条边. 算法 成功选择(n-1)条边后,形成一个棵最小生成树,当然如果算法无法选择出(n-1)条边,则说明原图不连通. 以下图为例: 边排

数据结构与算法系列----最小生成树(Prim算法&amp;amp;Kruskal算法)

 一:Prim算法       1.概览 普里姆算法(Prim算法).图论中的一种算法.可在加权连通图里搜索最小生成树.意即由此算法搜索到的边子集所构成的树中.不但包含了连通图里的全部顶点(英语:Vertex (graph theory)).且其全部边的权值之和亦为最小. 该算法于1930年由捷克数学家沃伊捷赫·亚尔尼克(英语:Vojtěch Jarník)发现.并在1957年由美国计算机科学家罗伯特·普里姆(英语:Robert C. Prim)独立发现:1959年,艾兹格·迪科斯彻再次发现了该

Kruskal算法(三)之 Java详解

前面分别通过C和C++实现了克鲁斯卡尔,本文介绍克鲁斯卡尔的Java实现. 目录 1. 最小生成树 2. 克鲁斯卡尔算法介绍 3. 克鲁斯卡尔算法图解 4. 克鲁斯卡尔算法分析 5. 克鲁斯卡尔算法的代码说明 6. 克鲁斯卡尔算法的源码 转载请注明出处:http://www.cnblogs.com/skywang12345/ 更多内容:数据结构与算法系列 目录 最小生成树 在含有n个顶点的连通图中选择n-1条边,构成一棵极小连通子图,并使该连通子图中n-1条边上权值之和达到最小,则称其为连通网的