最小生成树

记录用来复习。

----------------------------------------------------------------

PRIMER

整体思路:和Dijstrak差不多,都是用了简单的贪心策略,每次挑选距离生成树距离最近的没被合并进来的点作为吸收对象。

只是primer在松弛那一步上把距离的更新作为整体距离的更新而Dijstrak则是单原点的距离更新!!!

// primer.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include"iostream"
#include"vector"
#include"algorithm"
#include"queue"
#include"math.h"
#include"string"
#include"memory.h"
using namespace std;
#define max 100
#define inf 9999
int dis[max][max]={inf};
int visited[max]={0};
int n=0;
//和dijstrak算法一样,只是角度不一样。
int primer(int s)
{

	int sum=0;
	visited[s]=1;
	for(int k=0;k<n;k++)
	{//initial!!!
		int min=inf;
		int mark=-1;
		for(int i=0;i<n;i++)
		{ //find min
			if(visited[i]==0&&dis[s][i]<min)
			{
				min=dis[s][i];
				mark=i;
			}
		}
	    if(mark==-1) break;

		//visited
		visited[mark]=1;
		sum+=dis[s][mark];//多了一步统计

		for(int j=0;j<n;j++)
		{//updata
			if(visited[j]==0&&dis[s][j]>dis[mark][j])//把dis[s][j]看成是整体到其他各点的距离!!!这里和djs不同.
				dis[s][j]=dis[mark][j];
		}

	}
	return sum;
}

int main()
{
	int e=0;
	cin>>n>>e;
	int tempa=0,tempb=0,value;
	for(int i=0;i<100;i++)
		for(int j=0;j<100;j++)
			dis[i][j]=inf;
	for(int i=0;i<e;i++)
	{   //无向
		cin>>tempa>>tempb>>value;
		tempa--;
		tempb--;
		dis[tempa][tempb]=value;
		dis[tempb][tempa]=value;
	}
	cout<<primer(0)<<endl;
	return 0;
}

KRUSKAL

kruskal的思路也是贪心。但是和上面的primer不同,kruskal主要针对边的权大小来选择吸收的点。

简单来讲可以分成以下3步:

【1】根据边的权值大小来排序。

【2】检测候选边的端点是否来自同一集合。

【3】合并点,更新并查集。

// kruskal.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

#include"iostream"
#include"algorithm"
#include"vector"
#include"string"
#include"memory.h"
#include"stdlib.h"
#include"queue"

using namespace std;
#define max 100
int node[max]={0};
int e=0;
class road{
public:
	int a;
	int b;
	int value;
};

vector<road*> roads;

bool cmp(road* r1,road* r2)
{
	return r1->value<r2->value;
}
int find_set(int n)
{
   if(node[n]==-1)
	   return n;
   find_set(node[n]);
}

int  merge(int a,int b)
{
     if(a==b)
	    return 0;
	 else if(a>b)
	    node[a]=b;
	 else if(a<b)
		 node[b]=a;
	 return 1;

}

int  kruskal()
{   //sort edges
	sort(roads.begin(),roads.end(),cmp);
	int sum=0;
	for(int i=0;i<e;i++)
	{
		//find set
		int a=find_set(roads[i]->a);
		int b=find_set(roads[i]->b);
		//merge
		if(merge(a,b))//-1 is true!!
			sum+=roads[i]->value;
	}
	return sum;
}

int main()
{
	memset(node,-1,sizeof(node));
	cin>>e;
	int a=0,b=0,value=0;
	for(int i=0;i<e;i++)
	{
	  cin>>a>>b>>value;
	  road *r=new road;
	  r->a=a;
	  r->b=b;
	  r->value=value;
	  roads.push_back(r);
	}
	int sum=kruskal();
	cout<<sum<<endl;
	return 0;
}

测试数据:

9

14

1 2 4

1 8 8

2 3 8

2 8 11

3 4 7

3 6 4

3 9 2

4 5 9

4 6 14

5 6 10

6 7 2

7 8 1

7 9 6

8 9 7

out:37

时间: 2024-10-08 08:16:02

最小生成树的相关文章

次最小生成树 模版

次小生成树(转) 转载(http://www.cnblogs.com/z360/p/6875488.html) 所谓次小生成树,顾名思义就是从生成树中取出的第二小的生成树. 我们在前面已经说过最小生成树的概念及代码实现了,所以接下来要说的次小生成树应该比较简单理解了. 求次小生成树的两种方法 1:首先求出最小生成树T,然后枚举最小生成树上的边,计算除了枚举的当前最小生成树的边以外的所有边形成的最小生成树Ti,然后求最小的Ti就是次小生成树.2:首先计算出最小生成树T,然后对最小生成树上任意不相邻

HDU1863 畅通工程---(最小生成树)

畅通工程 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 27972    Accepted Submission(s): 12279 Problem Description 省政府"畅通工程"的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可).经过调查评估,得到的统计表中列出

51Nod1601 完全图的最小生成树计数

传送门 我居然忘写题解啦!(记忆废) 不管怎么说,这题还算是一道好题啊--你觉得敦爷出的题会有水题么 -- 这题比较容易把人误导到Boruvka算法之类的东西上去(我们机房去刚D题的人一开始大多也被误导了),但仔细思考之后是可以发现问题的特殊性质的. 听说很多人是从Kruskal算法想到这道题的做法的?好吧我并不是,那我就写写我的思考过程好了-- 记得算导上有一道思考题,判断一个最小生成树算法的正确性.那个算法是这样的:把当前图的点集随意划分成两半,递归两半后选出连接两个点集的边中权值最小的一条

最小生成树求法 Prim + Kruskal

prim算法的思路 和dijkstra是一样的 每次选取一个最近的点 然后去向新的节点扩张 注意这里的扩张 不再是 以前求最短路时候的到新的节点的最短距离 而是因为要生成一棵树 所以是要连一根最短的连枝 所以关键部分修改一下 dist[u] = min(dist[u], e.cost) --->>e是连接 v 和 u的边 同样地 普同写法O(v^2) 用队列优化后O(E*logV) 1 #include <iostream> 2 #include <stdio.h> 3

UVALive-7303- Aquarium【最小生成树】【连通块】

UVALive - 7303- Aquarium 题目链接:7303 题目大意:给你一个r * c的格子,每个格子有一个 ' \ ' 或者 '/' 的墙,以及打掉墙的费用,问使得所有块联通的最小费用.(看图好理解) 题目思路:就是将他化成一个图,联通的块相当于一个点,两个点之间有一条边,边的权值为墙的费用. 转化为连通块的思路是:每个格子看成两部分,左侧和右侧.以一行来看,假设两个格子A,B.那么B格子的右侧的编号一定和A格子的左侧的编号相同.如图所示 给每个格子的左右侧标上号,然后加入边,边的

BZOJ_1016_[JSOI2008]_最小生成树计数_(dfs+乘法原理)

描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1016 给出一张图,其中具有相同权值的边的数目不超过10,求最小生成树的个数. 分析 生成树的计数有一个什么什么算法... 我真的企图研究了...但是智商捉急的我实在看不懂论文... 所以最后还是写了暴力... 当然暴力也要靠正确的姿势的. 首先来看一个结论: 同一张图的所有最小生成树中,边权值相同的边的数目是一定的. 也就是说,假如某一张图的某一棵最小生成树由边权值为1,1,2,2,2,3的

poj1861 最小生成树 prim &amp; kruskal

// poj1861 最小生成树 prim & kruskal // // 一个水题,为的只是回味一下模板,日后好有个照应不是 #include <cstdio> #include <algorithm> #include <cstring> #include <vector> #include <iostream> using namespace std; const int MAX_N = 1008; const int INF =

hdu 1875 畅通工程再续(kruskal算法计算最小生成树)

畅通工程再续 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 18411    Accepted Submission(s): 5769 Problem Description 相信大家都听说一个"百岛湖"的地方吧,百岛湖的居民生活在不同的小岛中,当他们想去其他的小岛时都要通过划小船来实现.现在政府决定大力发展百岛湖,发展首先

【BZOJ】【1016】【JSOI2008】最小生成树计数

Kruskal/并查集+枚举 唉我还是too naive,orz Hzwer 一开始我是想:最小生成树删掉一条边,再加上一条边仍是最小生成树,那么这两条边权值必须相等,但我也可以去掉两条权值为1和3的,再加上权值为2和2的,不也满足题意吗?事实上,如果这样的话……最小生成树应该是1和2,而不是1和3或2和2!!! 所以呢?所以对于一个图来说,最小生成树有几条边权为多少的边,都是固定的!所以我们可以做一遍Kruskal找出这些边权,以及每种边权出现的次数.然后,对于每种边权,比方说出现了$v_i$

最小生成树 Prim(普里姆)算法和Kruskal(克鲁斯特尔)算法

Prim算法 1.概览 普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树.意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (graph theory)),且其所有边的权值之和亦为最小.该算法于1930年由捷克数学家沃伊捷赫·亚尔尼克(英语:Vojtěch Jarník)发现:并在1957年由美国计算机科学家罗伯特·普里姆(英语:Robert C. Prim)独立发现:1959年,艾兹格·迪科斯彻再次发现了该算法.因此,在某些场