您的位置:首页 > 其它

贪心策略之最小生成树中的kruskal 算法

2013-11-19 22:54 399 查看
在算法设计里面一个重要的策略就是贪心算法。贪心算法较之于动态规划是每一步求得的解是当前局部最优的解,这样一步步求下去那么所得到的解就会无限接近于全局的最优解,在某些情况下会等于最优解。



在这里主要谈谈贪心策略中的最小生成树。在嵌入式设计中,我们都会用线将各个component 连接起来,这里我们要保证每一个component 的每一个针脚我们都必须连上,这里做一个合理的假设,假设图论中的每一个节点就是component的针脚,而edge 就是连接的线,每一个线的长度和绕度等一些cost 则将它置为权重 w. 那么实际上我们已经把连接component的问题成功转化成了图论中节点、边和权重的问题了。 我们希望找到一个无环子集T(属于边集),即能够将所有的节点(针脚)连接起来,又具有最小的权重,由于子集T 是无环的,并且连接所有的节点,那么T 必然就是一个树。于是我们将由图生成的树称之为最小生成树。

而如何来生成这个树就是我接下来要讲的问题了。



假设集合A 是某颗最小生成树的一个子集,我们要做的事情就是选择一条连接2个节点边edge,将其加入到A 中,使得加入元素之后的A 依旧是某棵最小生成树的子集,由于我们可以将这条边安全的加入到子集A 中,那么称这样的边为安全边。现在剩下的就是辨别哪条边是安全边了。我们先看下图:



无向图G 的一个切割(S, V-S)是集合V 的一个划分,如果一条边的一个端点位于集合S, 而另一条边位于集合V-S,则称这条边横跨切割(S,V-S), 如果最小生成树集合A不存在横跨该切割的边,则称该切割尊重集合A 。在横跨一个切割的所有边中,权重最小的边称为轻量级边。

那么我们可以得出安全边的四个条件:

一:G 是连通无向图

二:A 包括在某棵最小生成树中

三:(S, V-S)是尊重集合A 的任意一个切割

四:边e 是横跨切割的一条轻量级边

结论:边e 是安全的

辨别安全边的理论已经分析完,那么我们下一步就是找出安全边了,在这里介绍kruskal 理论。

Kruskal理论认为将每一个结点看成是一个最小生成树,每次从图中找出权重最小的边,检查边两头的结点,如果结点分属于两个不同的集合,那么就进行合并操作,直到所有的边检测完。

#include <stdio.h>
#include <stdlib.h>
#define MAX 100
struct Vertex{
	char data;
	int rank;
	struct Vertex *parent;
};

typedef struct{
	struct Vertex *u;
	struct Vertex *v;
	int w;
}Edge;

struct Vertex vertex[MAX];
Edge edge[MAX];
/*
文件中的测试数据:注意数据的格式和函数getdata 中输入格式的匹配 
7
ABCDEFG
11
AB 7
AD 5
BC 8
BD 9
BE 7
CE 5
DE 15
DF 6
EF 8
EG 9
FG 11
*/
// return n is sum of edges
int GetData()
{
	int i ,n;
	char ch, ch2;
	FILE *fin ;
	fin = fopen("data.txt", "rb");
	// 文件中第一个数据是节点的总数 n 
	fscanf(fin, "%d\n", &n);
	for(i=0; i < n; i++)
	{
		fscanf(fin, "%c", &vertex[i].data);
		vertex[i].rank = 0;
		vertex[i].parent = &vertex[i];
	}
	// 随后输入的是边的总数 n 
	fscanf(fin, "%d\n", &n);// n is edge of sum
	for(i=0; i < n; i++)
	{
		fscanf(fin, "%c%c%d\n", &ch, &ch2, &edge[i].w);
		edge[i].u = &vertex[ch-'A'];
		edge[i].v = &vertex[ch2-'A'];
	}
	fclose(fin);
	return n;
}

int cmp(const Edge *a, const Edge *b)
{
	return (*a).w - (*b).w;
}

struct Vertex* Find_set(struct Vertex *x)
{
	if(x != x->parent)
		x->parent = Find_set(x->parent);
	return x->parent;
}

void Link(struct Vertex *x,struct Vertex *y)
{
	if(x->rank > y->rank)
		y->parent = x;
	else {
		x->parent = y;
		if(x->rank==y->rank)
			y->rank ++;
	}
}

void Union(struct Vertex *x, struct Vertex *y)
{
	Link(Find_set(x), Find_set(y));
}

void Kruskal(int n)
{
	int i;
	qsort(edge, n, sizeof(Edge), cmp);
	for(i = 0; i < n; i++)
	{
		if(Find_set(edge[i].u) != Find_set(edge[i].v))
		{
			printf("%c --- %c : %d \n", edge[i].u->data, edge[i].v->data, edge[i].w);
			Union(edge[i].u, edge[i].v);
		}
	}	
}

int main()
{
	Kruskal(GetData());
	system("pause");
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: