poj2458 Highways(最小生成树模版)

题目: https://vjudge.net/problem/POJ-2485

最小生成树算法(Prim算法讲得好): http://www.cnblogs.com/biyeymyhjob/archive/2012/07/30/2615542.html

这篇Kruskal算法讲得更清楚 : http://blog.csdn.net/luomingjun12315/article/details/47700237

1、Prim算法

1).输入:一个加权连通图,其中顶点集合为V,边集合为E;

2).初始化:Vnew = {x},其中x为集合V中的任一节点(起始点),Enew = {},为空;

3).重复下列操作,直到Vnew = V:

a.在集合E中选取权值最小的边<u, v>,其中u为集合Vnew中的元素,而v不在Vnew集合当中,并且v∈V(如果存在有多条满足前述条件即具有相同权值的边,则可任意选取其中之一);

b.将v加入集合Vnew中,将<u, v>边加入集合Enew中;

4).输出:使用集合Vnew和Enew来描述所得到的最小生成树。

//prim解
#include<stdio.h>
#include<set>
using namespace std;
const int qwq =  65536+10;
int size ;
const int n = 500+10;
set<int>v;//初始结点集合 
set<int>::iterator it;
int rs;
void build(int map[n][n])
{
	const int start = 0;
	while(!v.empty())	
	{
		it=v.begin();
		int k =*it;
		int min = qwq;
		//找距离v最近的结点 
		while(it!= v.end())
		{
			if(min>map[start][*it])
			{
				min=map[start][*it];
				k=*it;	
			}	
			it++; 
		}
//		printf("最短的:%d->长度%d\n",k,min);1
		if(rs<min)
		{
			rs=min;
		}
		int newstart = k;
		for(int i =0;i<size;i++)
		{
			if(map[start][i]>map[k][i])
			{
				map[start][i]=map[k][i];
			}
		}
		v.erase(k);
	}
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&size);
		int map[n][n];
//		{
//			{0,7,qwq,5,qwq,qwq,qwq},
//			{7,0,8,9,7,qwq,qwq},
//			{qwq,8,0,qwq,5,qwq,qwq},
//			{5,9,qwq,0,15,6,qwq},
//			{qwq,7,5,15,0,8,9},
//			{qwq,qwq,qwq,6,8,0,11},
//			{qwq,qwq,qwq,qwq,9,11,0}
//		};
		
		for(int i=0;i<size;i++)
		{
			for(int j=0;j<size;j++)
			{
				scanf("%d",&map[i][j]);
			}
		}
		rs=-1;
		for(int i=1;i<size;i++)
		{
			v.insert(i);
		}
		build(map);
		printf("%d\n",rs);
	}
	return 0;
} 


2、Kruskal算法描述

      Kruskal算法是基于贪心的思想得到的。首先我们把所有的边按照权值先从小到大排列,接着按照顺序选取每条边,如果这条边的两个端点不属于同一集合,那么就将它们合并,直到所有的点都属于同一个集合为止。至于怎么合并到一个集合,那么这里我们就可以用到一个工具——-并查集(不知道的同学请移步:Here)。换而言之,Kruskal算法就是基于并查集的贪心算法。

//kruskal 把边按权值从小到大排序,从小到大 遍历每一条边, 如果边的两个端点不再同一个联通分支中,就连接起来 
#include<stdio.h>
#include<algorithm> 
#include<memory.h>
using namespace std;
struct Node
{
	int from;
	int to;
	int wei;
};
//int cmp(Node a,Node b)
//{
//	return a.wei<b.wei;
//}
int cmp(const void *a,const void *b)
{
	Node aa = *(Node*)a;
	Node bb = *(Node*)b;
	return aa.wei-bb.wei;
}
//-----------并查集部分 -----------
int pre[500+10];
int find(int x)
{
	int r= x;
	while(pre[r]!=r)
	{
		r=pre[r];
	}
	int i=x,j;
	while(i!=r)
	{
		j= pre[i];	
		pre[i]=r;
		i=j;
	} 
	return r;
}
void join(int a,int b)
{
	int fa=find(a);
	int fb=find(b);
	if(fa!=fb)
	{
		pre[fa]=fb;
	}
}
//------------------
const int size = (500+1)*500/2;
int s;
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		memset(pre,0,sizeof(pre));
		s=0;
		Node edge[size];
		int n;
		scanf("%d",&n);
		for(int i=0;i<n;i++)
		{
			pre[i]=i;
		}
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<n;j++)
			{
				int a;
				scanf("%d",&a);
				if(i<j) //输入每一条边的信息 
				{
					edge[s].from=i;
					edge[s].to=j;
					edge[s].wei=a;
					s++;
				}
			}
		}	
		qsort(edge,s,sizeof(edge[0]),cmp); 
//		sort(edge,edge+s,cmp);
		int rs = -1;
		int t=0; 
		for(int i=0;i<s;i++)
		{
			int from = edge[i].from;
			int to = edge[i].to;
			if(find(from)!=find(to))//不在同一个集合,合并 
			{
				join(from,to);
				if(rs<edge[i].wei)
				{
					rs=edge[i].wei;
				}
				t++;//连接的边数 
			}
			if(t==n-1){//全部的点已经连在一起了 
				break;
			}
		}
		printf("%d\n",rs);
	}
	return 0; 
}




猜你喜欢

转载自blog.csdn.net/zark721/article/details/78439496