A:生成树
B:未被访问过的点的集合
pre[i]:生成树中i的前驱节点。
A中的dis[i]:生成树中包含点i的边的长度。
B中的dis[i]: i到A的最短距离
vis[]:标记是否遍历过(是否属于A)
Prim算法的思想
1.任选一点,不妨选择第一个点,加入生成树A。
2.遍历B,寻找一点u,使其到A的距离最小(就是A中也找了一点v)。添加u到A中(vis)。记录这条边及其权值(pre,dis)。
3.更新与u相连的点的dis和pre
4.循环直到遍历所有可达的点。
View Code
#include <iostream> #include <climits> using namespace std; #define Max 100 void Prim(int n, int map[Max][Max], int dis[Max], int pre[Max]) { bool visit[Max]; //初始化 for (int i = 2; i <= n; ++i) { visit[i] = false; dis[i] = map[1][i]; pre[i] = 1; } visit[1] = true; dis[1] = 0; //循环n-1次,每次加入一个点 for (int i = 1; i < n; ++i) { int min = INT_MAX; int next = 0; //找到最小边 for (int j = 2; j <= n; ++j) { if (!visit[j] && dis[j] < min) { min = dis[j]; next = j; } } //找不到 if (next == 0)return; //加入生成树 visit[next] = true; //更新与k相邻的顶点。 for (int j = 2; j <= n; j++) { if (!visit[j] && map[j][next] < INT_MAX && dis[j] > map[j][next]) { dis[j] = map[j][next]; pre[j] = next; } } } }
基本的最小生成树题目。
View Code
/* 【题目来源】 http://soj.me/1090 最小生成树。 【题目分析】 给定邻接矩阵,求最小生成树的最长边。 【思路分析】 prim算法。 */ #include <iostream> #include <algorithm> #include <iterator> #include <cstring> #include <climits> using namespace std; #define Max 502 int map[Max][Max], dis[Max], pre[Max]; bool Prim(int n) { bool vis[Max]; //初始化 for (int i = 2; i <= n; ++i) { dis[i] = map[1][i]; vis[i] = false; pre[i] = 1; } vis[1] = true; dis[1] = 0; //循环n-1次 for (int i = 1; i < n; ++i) { int min = INT_MAX; int k = 0; //找到最小边 for (int j = 2; j <= n; ++j) { if (min > dis[j] && !vis[j]) { min = dis[j]; k = j; } } //找不到 if (k == 0) return false; //加入生成树 vis[k] = true; //更新其他各点 for (int j = 1; j <= n; ++j) { if (!vis[j] && map[k][j] < dis[j] && map[j][k] != INT_MAX) { dis[j] = map[k][j]; pre[j] = k; } } } } int main() { int n; int m; cin >> m; int m2 = m; while (m--) { if (m != m2-1) cout << endl; cin >> n; memset(dis, 0, sizeof(dis)); for (int i = 1; i <= n; ++i) { for (int j = 1; j <= n; ++j) { cin >> map[i][j]; } } Prim(n); cout << *max_element(dis, dis+n+1) << endl; } }