Kruskal算法实例练习(一)

Kruskal算法练习

剑鱼行动

题目来源:ZhejiangUniversity Local Contest 2002,Preliminary,ZOJ1203

题目描述:

——给定平面上N个城市的位置,计算连接这N个城市所需线路长度总和的最小值。

输入描述:

——输入文件中包含多个测试数据。每个测试数据的第1行为一个正整数N0N≤100,代表需要连接的城市数目;接下来有N行,每行为两个实数XY-10000≤X,Y≤10000,表示每个城市的X坐标和Y坐标。输入文件中最后一行为N=0,代表输入结束。

输出描述:

——对输入文件中每个测试数据,计算连接所有城市所需线路长度总和的最小值。每对城市之间的线路为连接这两个城市的直线。输出格式为:第1行为“Case#n:,其中n为测试数据的序号,序号从1开始计起;第2行为“Theminimal distance is: d”,其中d为求得的最小值,精确到小数点后两位有效数字。每两个测试数据的输出之间输出一个空行。

样例输入:                                   样例输出:

5                                                 Case#1:

0 0                                              The minimal distance is:2.83

0 1

1 1

1 0

0.5 0.5

0

解:此题中,任意两个顶点之间都有边连通,权值为这两个顶点之间的距离。将所有边求出并存储到边的数组edges中后,按照Kruskal算法求解即可~

Code

#include
#include
#include

#define MAXN 100	//顶点个数的最大值
#define MAXM 500	//边的个数的最大值
typedef struct edge		//边
{
	int u, v;	//边的顶点
	double w;	//权值(两个点之间的距离)
}edge;
edge edges[MAXM];		//边的数组
int parent[MAXN];	//parent[i]为顶点i所在集合对应的树中的根结点
int n, m;		//顶点个数、边的个数
double X[MAXN], Y[MAXN];//每个顶点的X坐标和Y坐标
int i, j;		//循环变量
double sumweight;	//生成树的权值
void UFset()		//初始化
{
	for(i = 0; i = 0; s = parent[s]) ;
	while(s != x)	//压缩路径
	{
		int tmp = parent[x];
		parent[x] = s;
		x = tmp;
	}
	return s;
}
//将两个不同集合的元素进行合并,使两个集合中任意两个元素都能连通
void Union(int R1, int R2)
{
	int r1 = Find(R1), r2 = Find(R2);//求根结点
	int tmp = parent[r1]+parent[r2]; //两个集合合并后的元素个数的相反数
	if(parent[r1] > parent[r2])
	{
		parent[r1] = r2;
		parent[r2] = tmp;
	}
	else
	{
		parent[r2] = r1;
		parent[r1] = tmp;
	}
}
int cmp(const void *a, const void *b)   //注意此处,因为aa.w为浮点数,所以二者之差不能作为返回值来进行判断和排序~
{
	edge aa = *(const edge *)a, bb = *(const edge *)b;
	if(aa.w > bb.w) return 1;
	else return -1;
}
void Kruskal()
{
	int num = 0;			//已选用的边的数目
	UFset();
	for(i = 0; i < m; i++)
	{
		if(Find(edges[i].u) != Find(edges[i].v))
		{
			sumweight += edges[i].w; num++;
			Union(edges[i].u,edges[i]. v);
		}
		if(num >= n-1) break;
	}
}
int main()
{
	int count = 1;			//数据组数
	while(1)
	{
		scanf("%d", &n);
		if(n == 0) break;
		for(i = 0; i < n; i++)
			scanf("%lf%lf", &X[i], &Y[i]);
		int mi = 0;
		for(i = 0; i < n; i++)	//构造数组数据
		{
			for(j = i+1; j < n; j++)
			{
				edges[mi].u = i; edges[mi].v = j;
				edges[mi].w = sqrt((X[i]-X[j])*(X[i]-X[j])+(Y[i]-Y[j])*(Y[i]-Y[j]));
				mi++;
			}
		}
		m = mi;			//边数
		qsort(edges, m, sizeof(edges[0]), cmp);
		sumweight = 0.0;
		Kruskal();
		if(count > 1) printf("\n");
		printf("Case #%d:\n", count);
		printf("The minimal distance is: %0.2f\n", sumweight);
	}
	return 0;
}
运行结果:

Kruskal算法实例练习(一)_第1张图片

你可能感兴趣的:(狂奔のC/C++,狂奔の数据结构与算法,数据结构与算法随笔)