c++之最小生成树篇
C++之
最小生成树篇
概念:一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边。 最小生成树可以用kruskal(克鲁斯卡尔)算法或prim(普里姆)算法求出。在一给定的无向图G = (V, E) 中,(u, v) 代表连接顶点 u 与顶点 v 的边(即),而 w(u, v) 代表此边的权重,若存在 T 为 E 的子集(即)且为无循环图,使得的 w(T) 最小,则此 T 为 G 的最小生成树。最小生成树其实是最小权重生成树的简称。
应用:生成树和最小生成树有许多重要的应用。
例如:要在n个城市之间铺设光缆,主要目标是要使这 n 个城市的任意两个之间都可以通信,但铺设光缆的费用很高,且各个城市之间铺设光缆的费用不同,因此另一个目标是要使铺设光缆的总费用最低。这就需要找到带权的最小生成树。
算法:最小生成树有两种算法:1、kruskal(克鲁斯卡尔)算法 和 prim(普里姆)算法
1、prim(普里姆)算法:
prim算法采用与dijkstra、bellman-ford算法一样的“蓝白点”思想。
所谓“蓝白点”思想就是:“白点代表已经进入最小生成树的点,蓝点表示为进入最小生成树的点。”
算法描述:
1).输入:一个加权连通图,其中顶点集合为V,边集合为E;
2).初始化:Vnew= {x},其中x为集合V中的任一节点(起始点),Enew= {},为空;
3).重复下列操作,直到Vnew= V:
a.在集合E中选取权值最小的边<u, v>,其中u为集合Vnew中的元素,而v不在Vnew集合当中,并且v∈V(如果存在有多条满足前述条件即具有相同权值的边,则可任意选取其中之一);
b.将v加入集合Vnew中,将<u, v>边加入集合Enew中;
4).输出:使用集合Vnew和Enew来描述所得到的最小生成树。
2、kruskal(克鲁斯卡尔)算法:
kruskal(克鲁斯卡尔)算法是一种巧妙利用并查集来求最小生成树的算法。
假设 WN=(V,{E}) 是一个含有 n 个顶点的连通网,则按照克鲁斯卡尔算法构造最小生成树的过程为:先构造一个只含 n 个顶点,而边集为空的子图,若将该子图中各个顶点看成是各棵树上的根结点,则它是一个含有 n 棵树的一个森林。之后,从网的边集 E 中选取一条权值最小的边,若该条边的两个顶点分属不同的树,则将其加入子图,也就是说,将这两个顶点分别所在的两棵树合成一棵树;反之,若该条边的两个顶点已落在同一棵树上,则不可取,而应该取下一条权值最小的边再试之。依次类推,直至森林中只有一棵树,也即子图中含有 n-1条边为止。
实际应用:
最优布线问题就是一个典型的用最小生成树的例子:
问:
学校有n台计算机,为了方便数据传输,现要将它们用数据线连接起来。两台计算机被连接是指它们中间有数据线连 接。由于计算机所处的位置不同,因此不同的两台计算机的连接费用往往是不同的。当然,如果将任意两台计算机都用数据线连接,费用将是相当庞大的。为了节省费用,我们采用数据的间接传输手段,即一台计算机可以间接的通过若干台计算机(作为中转)来实现与另一台计算机的连接。现在由你负责连接这些计算机,你的任务是使任意两台计算机都连通(不管是直接的或间接的)。
解:
这道题可以用到prim算法,prim算法就是运用贪心算法,来生成最小生成树。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int g[101][101];
int minn[101];
bool u[101];
int n,j,i;
int main()
{
cin>>n;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
cin>>g[i][j];
memset(minn,0x7f,sizeof(minn));
minn[1]=0;
memset(u,1,sizeof(u));
for(i=1;i<=n;i++)
{
int k=0;
for(j=1;j<=n;j++)
if(u[j]&&(minn[j]<minn[k]))
k=j;
u[k]=false;
for(j=1;j<=n;j++)
if(u[j]&&(g[k][j]<minn[j]))
minn[j]=g[k][j];
}
int total=0;
for(i=1;i<=n;i++)
total+=minn[i];
cout<<total<<endl;
return 0;
}
#include<cstdio>
#include<cstring>
using namespace std;
int g[101][101];
int minn[101];
bool u[101];
int n,j,i;
int main()
{
cin>>n;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
cin>>g[i][j];
memset(minn,0x7f,sizeof(minn));
minn[1]=0;
memset(u,1,sizeof(u));
for(i=1;i<=n;i++)
{
int k=0;
for(j=1;j<=n;j++)
if(u[j]&&(minn[j]<minn[k]))
k=j;
u[k]=false;
for(j=1;j<=n;j++)
if(u[j]&&(g[k][j]<minn[j]))
minn[j]=g[k][j];
}
int total=0;
for(i=1;i<=n;i++)
total+=minn[i];
cout<<total<<endl;
return 0;
}
济南稼轩学校
39级10班 续尧