图论:Prim算法 求最小生成树
Prim算法 求最小生成树
利用了蓝白点思想,先将所有点标记为蓝点。用一个数组布尔数组b 标记点的蓝白,如果为true就是蓝点,否则是白点。先定义一个整型变量mst=0,mst就是最小生成树。然后用一个二维数组w 记录 边i和边j之间的权值,再用一个一维数组mins 记录的是蓝点的最小边权,这个mins数组是关键。
int w[51][51];//边的权值
int mins[51];//蓝点的最小边权
bool b[51];//蓝点标记
int mst = 0;//最小生成树的边权和
然后将所有点都初始化为蓝点,并且将每个点的最小边权先初始化为无穷大,因为是求最小生成树。
for (int i = 0; i <= n; ++i)
{
mins[i] = oo;//最小边权初始化为最大
b[i] = true;//全部初始化为蓝点
}//i等于0的点要初始化 方便后面每次比较找到一个最小的蓝点
然后先初始化所有点的边权为无穷大,然后再输入边权,这样两个点之间有边相连就有边权,否则两个点之间的边权就是无穷大。
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j)
w[i][j] = oo;//先初始化边的权值为无穷
int x, y, z;
for (int i = 1; i <= m; ++i)
{
cin >> x >> y >> z;
w[x][y] = w[y][x] = z;//存储权值
}
然后任选一个点开始,开始的点就把它的最小边权设为0,初始化mins[开始点]=0,我们一般选1为起点。
mins[1] = 0;//任选一点开始
然后就要一个外层循环,循环n个点,每次循环都要选出一个边权最小的蓝点,所以要再加一个内层循环寻找mins值最小的点,把最小边权加入mst,就相当于把这条边加入了最小生成树,因为第一次mins[1]=0,所以第一次相当于不加入边,所以一共加入n-1条边,刚好是最小生成树的边数,并且更新所有与选出的蓝点邻接的蓝点的最小边权mins值,因为更新,所以要再内层并列一个内层循环,遍历所有邻接的蓝点,更新的转移方程就是用蓝点和邻接点的蓝点的边权代替mins[邻接点],但前提是边权要更小才能更新。注意每次选出来蓝点后要把蓝点洗白,避免重复选。
for (int i = 1; i <= n; ++i)
{
//找到mins[k]值最小的蓝点
int k = 0;//初始化一个比较的点
for (int j = 1; j <= n; ++j)
if (b[j] && mins[j] < mins[k])
k=j;//替换之
b[k] = 0;//洗白找到的蓝点
mst += mins[k];//累加生成树权值
//修改与找到的蓝点k相连的所有蓝点
for (int j = 1; j <= n; ++j)//枚举所有点
{
if (b[j] && w[k][j] < mins[j])
mins[j] = w[k][j];
}
}
完整代码:
1 #include<iostream>
2 using namespace std;
3 int w[51][51];//边的权值
4 int mins[51];//蓝点的最小边权
5 bool b[51];//蓝点标记
6 int mst = 0;//最小生成树的边权和
7 int main()
8 {
9 int n, m;//n个点 m条边
10 cin >> n >> m;
11 int oo = 0x7fffff;
12 for (int i = 1; i <= n; ++i)
13 for (int j = 1; j <= n; ++j)
14 w[i][j] = oo;//先初始化边的权值为无穷
15 int x, y, z;
16 for (int i = 1; i <= m; ++i)
17 {
18 cin >> x >> y >> z;
19 w[x][y] = w[y][x] = z;//存储权值
20 }
21 for (int i = 0; i <= n; ++i)
22 {
23 mins[i] = oo;//最小边权初始化为最大
24 b[i] = true;//全部初始化为蓝点
25 }//i等于0的点要初始化 方便后面每次比较找到一个最小的蓝点
26 mins[1] = 0;//任选一点开始
27 for (int i = 1; i <= n; ++i)
28 {
29 //找到mins[k]值最小的蓝点
30 int k = 0;//初始化一个比较的点
31 for (int j = 1; j <= n; ++j)
32 if (b[j] && mins[j] < mins[k])
33 k=j;//替换之
34 b[k] = 0;//洗白找到的蓝点
35 mst += mins[k];//累加生成树权值
36
37 //修改与找到的蓝点k相连的所有蓝点
38 for (int j = 1; j <= n; ++j)//枚举所有点
39 {
40 if (b[j] && w[k][j] < mins[j])
41 mins[j] = w[k][j];
42 }
43
44 }
45 cout << mst;
46 return 0;
47 }