最小生成树 dijkstra算法模板 floyd算法模板 POJ 1287 Networking

最小生成树

定义:给定一张带权无向图,G = (V, E), n = |V|, m = |E|. 由V中全部n个顶点和E中n - 1 条变构成的无向连通子图被称为G的一棵最小生成树。
算法prime 算法 和 Kruskal算法

  • Kruskal
    任意时刻, 每次选取给定的边中最短的一条边,加入到森林中,直到加完全部的边。加边过程用并查集添加。
    添加最短边的方法按照边的权值从小到大排序,然后从第一个开始添加点,直到把所有的点都添加到森林中。

  • Prime
    从第一个点(起点)开始,每次在所给的点中查找距离当前点最短的点,dis 数组代表距离起点的距离。然后把它们权值累加,每次选取一个点都要将dis数组更新。

最小生成树模板练习题
POJ1287

Sample Input

1 0

2 3
1 2 37
2 1 17
1 2 68

3 7
1 2 19
2 3 11
3 1 7
1 3 5
2 3 89
3 1 91
1 2 32

5 7
1 2 5
2 3 7
2 4 8
4 5 11
3 5 10
1 5 6
4 2 12

0

Sample Output

0
17
16
26

题目要求连通全部点所用的最短路径
Kruskal算法模板

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
const int N = 110;
int par[N];
int rank[N];
int n, m;
struct node{
	int x, y, dis;
}map[3010];
void init(int n){
	for(int i = 0; i <=  n; i++){
		par[i] = i;
		rank[i] = 0;
	}
		
}
int find(int x){
	if(par[x] == x) return x;
	return par[x] = find(par[x]);
}
void unite(int x, int y){
	x = find(x);
	y = find(y);
	
	if(x == y)
	return ;
	if(rank[x] < rank[y])
		par[x] = y;
	else {
		par[y] = x;
		if(rank[x] == rank[y])
			rank[x]++;
	}
	return ;
}
bool cmp(node x, node y){
	return x.dis < y.dis;
}
int main(){
		while(scanf("%d%d", &n, &m) != EOF && n){
			int cnt = 1;
			init(n);
			memset(map, 0, sizeof map);
			int ans = 0;
			for(int i = 1; i <= m; i++){
				int x, y, z;
				cin >> x >> y >> z;
				map[i].x = x;
				map[i].y = y;
				map[i].dis = z;
			}
			sort(map + 1, map + m + 1, cmp);
			for(int i = 1; i <= m; i++){
				int x = find(map[i].x);
				int y = find(map[i].y);
				if(x != y){
					cnt++;	
					ans += map[i].dis;	
					unite(map[i].x, map[i].y);
				}
				if(cnt >= n) break;	//判断是否已经添加完所有的点
			}
			cout << ans << endl;
		}
	return 0;
}

prime算法模板

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
const int inf = 0x3f3f3f3f;
const int N = 110;
int n;
int cost[N][N], dis[N];
bool vis[N];
char c1, c2;
int m, x, y, z;
int prime(){
	for(int i = 1; i <= n; i ++ ) dis[i] = cost[1][i];
	memset(vis, false, sizeof vis);	
	dis[1] = 0;
	vis[1] = 1;
	int ans = 0;
	for(int i = 1; i < n; i++){
		int minx = inf;
		int p = -1;
		for(int j = 2; j <= n; j++){
			if(!vis[j] && dis[j] < minx){
				minx = dis[j];
				p = j;
			}
		}
		if(p == -1) break;
		vis[p] = 1;
		ans += dis[p];
 		for(int j = 1; j <= n; j++){
			if(!vis[j] && dis[j] > cost[p][j])
				dis[j] = cost[p][j];
		}
	}
	return ans;
}
int main(){
		while(scanf("%d%d", &n, &m) != EOF && n){
			for(int i = 0; i <= n; i++)
			for(int j = 0; j <= n; j++)
				if(i == j) cost[i][j]  = 0;
				else cost[i][j] = inf;
			for(int i = 1; i <= m; i++){
				int x, y, z;
				cin >> x >> y >> z;
				cost[x][y] = cost[y][x] = min(cost[x][y], z);
			}
	
			cout << prime() << endl;
		}
	return 0;
}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值