acm专题学习之生成树(一)最小生成树入门+POJ1251

题意:给你n个点,右n-1条边,每个边都有一个权值,让你求出最小生成树

扩展:最小生成树

最小生成树的概念:在一副加权连通图中,最小生成树包含原图中的所有 n 个结点且权值和最小,并且有保持图连通的最少的边(说的就是不会成环)。

解决最小生成树的算法:prime和kruskal算法

prime算法:

  • 先任意选择一条边(一般直接选择第一条),连接与其相连权值最小的点,然后两个点成为一个集合体。
  • 找这个不在这个集合体里 但是与集合体相连的权值最小的点 与集合体相连,并把该点归入集合体。
  • 重复上一条操作,直到集合体归入了所有的点

kruskal算法:

  • 先选择一条权值最小的边,把这条边相连的两个点归成一个集合。
  • 再找下一个权值最小的边,但是边相连的两个点不能属于同一个集合,把这条边相连的两个点(这里也可以是集合)归成一个集合
  • 重复上一条操作,直到最后只有一个集合体且归入所有的点。

两个的区别:

  1. 集合的个数:prime算法自始自终只有一个集合,而kruskal算法可以有多个集合,所以kruskal算法要用到并查集。
  2. 选取的方式:prime算法先是任意选取,再根据选取已有的基础上选取权值最小且不在集合的点(取点)。kruskal算法则是每次以权值最小的边来选取,可以有多个集合(取边)。

本题代码:

prime算法:

#include 
#include 
#include 
using namespace std;
const int maxn = 30;
const int inf = 0x3f3f3f3f;
int mp[maxn][maxn], vis[maxn], ans[maxn];//采用邻接矩阵存道路关系
int n;
void prime()
{
    int sum=0;
	for (int i = 1; i <= n; i++)//先选第一个点为集合
	{
		vis[i] = 0;
		ans[i] = mp[1][i];//存与第一个点成的集合到相连的点的权值
	}
    vis[1]=1;
	for (int i = 1; i <= n; i++)
	{
		int min1 = inf,p=0;
		for (int j = 1; j <= n; j++)
		{
			if (!vis[j] && ans[j] < min1)//找出不属于集合,但是相连权值最小的点
			{
				min1 = ans[j];
				p = j;
			}
		}
		if(min1==inf)break;//如果找不到了,就说明已经找完了,这里找的次数是n,如果没有这个条件很容易把inf算入
		//cout<>n,n)
	{
		memset(mp, inf, sizeof(mp));
		for (int i = 1; i 

kruskal算法:

#include 
#include 
#include 
#include 
using namespace std;
const int maxn = 35;
const int inf = 0x3f3f3f3f;
int vis[maxn];//并查集数组
int num;
struct node//用该结构存道路关系
{
    int a,b;
    int val;
}mp[maxn*maxn];
int n;
bool cmp(node a,node b)
{
    return a.val>n,n)
	{
	    num=0;
		for (int i = 1; i 

 

你可能感兴趣的:(acm算法学习,acm算法之图论)