机试算法讲解:第34题 并查集之求最短公路总长度

/*
问题:有任意两个村庄的距离,使全省任意两个村庄之间都可以畅通(不要求直接相连,间接联通也可以),要求铺设公路最短和次最短。请计算最小公路总长度
输入:第一行给出村庄数N(<100),随后的N(N-1)/2给出村庄之间的距离,每行给出一对正整数,分别是两个村庄的编号,以及两个村庄之间的距离。村庄从1到N编号,N=0时结束
输出:求出最短公路总长度
输入:
3
1 2 1
1 3 2
2 3 4
4
1 2 1
1 3 4
1 4 1
2 3 3
2 4 2
3 4 5
0
输出:
3 
5
思路:利用并查集,这里要设置一条边来进行比较
关键:快速排序edge[low] <=iPos <= edge[high],而不是edge[low] < iPos,需要重载<=,而不是<
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define N 1000
int Tree[N];

//设定边结构体
typedef struct Edge
{
	int _iV1,_iV2;//设定边的起始节点
	int _iWeight;//设定权重
	//快速排序必须重载<=而不是<
	bool operator <= (const Edge& edge)
	{
		return _iWeight <= edge._iWeight;
	}
}Edge;

//并查集寻找根结点的路径压缩函数
int findRoot(int x)
{
	if(-1==Tree[x])
	{
		return x;
	}
	else
	{
		//寻找当前节点父节点的根结点
		int iRoot = findRoot(Tree[x]);
		//设定当前节点的父节点为根结点
		Tree[x] = iRoot;
		//返回父节点
		return iRoot;
	}
}

//这个快速排序有问题,小于等于需要动

int partition(Edge* edge,int low,int high)
{
	Edge iPos = edge[low];
	while(low < high)
	{
		while(low < high && iPos <= edge[high])
		{
			high--;
		}
		edge[low] = edge[high];//比枢轴小的元素移动到左端
		while(low < high && edge[low] <= iPos)
		{
			low++;
		}
		edge[high] = edge[low];//比枢轴大的元素移动到右端
	}
	edge[low] = iPos;
	return low;
}

void quickSort(Edge* edge,int low,int high)
{
	if(low < high)
	{
		int iPos = partition(edge,low,high);
		quickSort(edge,low,iPos-1);
		quickSort(edge,iPos+1,high);
	}
}


int main(int argc,char* argv[])
{
	int iNum,i;
	while(EOF!=scanf("%d",&iNum) && iNum!=0)
	{
		//int iV1,iV2,iWeight;
		//获取输入信息
		Edge edgeArr[100];
		//初始化并查集
		for(i = 0 ; i < N ; i++)
		{
			Tree[i] = -1;
		}
		//for(i = 0 ; i < iNum ; i++),这里的边总共有iNum*(iNum-1),初始时进行根结点归并,最多只需要iNum*(iNum-1)/2-1条边
		for(i = 0 ; i < iNum*(iNum-1)/2; i++)
		{
			scanf("%d %d %d",&edgeArr[i]._iV1,&edgeArr[i]._iV2,&edgeArr[i]._iWeight);
			/*
			iV1 = findRoot(iV1);
			iV2 = findRoot(iV2);
			if(iV1!=iV2)
			{
				Tree[iV1] = iV2;
			}
			*/
		}

		//进行按权值进行快速排序边,易错,边的个数是iNum*(iNum-1)/2
		quickSort(edgeArr,0,iNum*(iNum-1)/2-1);
		int iWeightSum = 0 ;
		for(i = 0 ; i < iNum*(iNum-1)/2 ; i++)
		{
			int iRoot1 = findRoot(edgeArr[i]._iV1);
			int iRoot2 = findRoot(edgeArr[i]._iV2);
			if(iRoot1!=iRoot2)
			{
				Tree[iRoot1] = iRoot2;
				iWeightSum += edgeArr[i]._iWeight;
			}		
		}
		printf("%d\n",iWeightSum);
	}
	system("pause");
	getchar();
	return 0;
}
/*
问题:有任意两个村庄的距离,使全省任意两个村庄之间都可以畅通(不要求直接相连,间接联通也可以),要求铺设公路最短和次最短。请计算最小公路总长度
输入:第一行给出村庄数N(<100),随后的N(N-1)/2给出村庄之间的距离,每行给出一对正整数,分别是两个村庄的编号,以及两个村庄之间的距离。村庄从1到N编号,N=0时结束
输出:求出最短公路总长度
输入:
3
1 2 1
1 3 2
2 3 4
4
1 2 1
1 3 4
1 4 1
2 3 3
2 4 2
3 4 5
0
输出:
3 
5
思路:利用并查集,这里要设置一条边来进行比较
关键:快速排序edge[low] <=iPos <= edge[high],而不是edge[low] < iPos,需要重载<=,而不是<
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define N 1000
int Tree[N];

//设定边结构体
typedef struct Edge
{
	int _iV1,_iV2;//设定边的起始节点
	int _iWeight;//设定权重
	//快速排序必须重载<=而不是<
	bool operator <= (const Edge& edge)
	{
		return _iWeight <= edge._iWeight;
	}
}Edge;

//并查集寻找根结点的路径压缩函数
int findRoot(int x)
{
	if(-1==Tree[x])
	{
		return x;
	}
	else
	{
		//寻找当前节点父节点的根结点
		int iRoot = findRoot(Tree[x]);
		//设定当前节点的父节点为根结点
		Tree[x] = iRoot;
		//返回父节点
		return iRoot;
	}
}

//这个快速排序有问题,小于等于需要动

int partition(Edge* edge,int low,int high)
{
	Edge iPos = edge[low];
	while(low < high)
	{
		while(low < high && iPos <= edge[high])
		{
			high--;
		}
		edge[low] = edge[high];//比枢轴小的元素移动到左端
		while(low < high && edge[low] <= iPos)
		{
			low++;
		}
		edge[high] = edge[low];//比枢轴大的元素移动到右端
	}
	edge[low] = iPos;
	return low;
}

void quickSort(Edge* edge,int low,int high)
{
	if(low < high)
	{
		int iPos = partition(edge,low,high);
		quickSort(edge,low,iPos-1);
		quickSort(edge,iPos+1,high);
	}
}


int main(int argc,char* argv[])
{
	int iNum,i;
	while(EOF!=scanf("%d",&iNum) && iNum!=0)
	{
		//int iV1,iV2,iWeight;
		//获取输入信息
		Edge edgeArr[100];
		//初始化并查集
		for(i = 0 ; i < N ; i++)
		{
			Tree[i] = -1;
		}
		//for(i = 0 ; i < iNum ; i++),这里的边总共有iNum*(iNum-1),初始时进行根结点归并,最多只需要iNum*(iNum-1)/2-1条边
		for(i = 0 ; i < iNum*(iNum-1)/2; i++)
		{
			scanf("%d %d %d",&edgeArr[i]._iV1,&edgeArr[i]._iV2,&edgeArr[i]._iWeight);
			/*
			iV1 = findRoot(iV1);
			iV2 = findRoot(iV2);
			if(iV1!=iV2)
			{
				Tree[iV1] = iV2;
			}
			*/
		}

		//进行按权值进行快速排序边,易错,边的个数是iNum*(iNum-1)/2
		quickSort(edgeArr,0,iNum*(iNum-1)/2-1);
		int iWeightSum = 0 ;
		for(i = 0 ; i < iNum*(iNum-1)/2 ; i++)
		{
			int iRoot1 = findRoot(edgeArr[i]._iV1);
			int iRoot2 = findRoot(edgeArr[i]._iV2);
			if(iRoot1!=iRoot2)
			{
				Tree[iRoot1] = iRoot2;
				iWeightSum += edgeArr[i]._iWeight;
			}		
		}
		printf("%d\n",iWeightSum);
	}
	system("pause");
	getchar();
	return 0;
}

你可能感兴趣的:(并查集,机试算法)