本次,我主要给大家讲一讲有关这一题的Prim算法
首先我们来讨论一下:
什么是最小生成树?
- 无回路,且包含原图中的n-1条边。
- 包含原图中的全部顶点。
- 边的权重和在所有其他生成树中最小。
- 最小生成树存在,则该图一定连通。反过来一样,图连通,则最小生成树一定存在
那么如何构建满足以上条件的生成树?
Prim算法构建最小生成树,
简单来说就是在图中,从某一顶点出发,逐步构建,让一棵小树逐渐长大。
用一个例子来说明更清晰点吧!首先看下面一张无向网图:
要构造这张图的最小生成树,首先,假设我们从V0顶点开始出发,
也就是以V0为根结点开始建树,接着往外扩展,从与V0顶点相邻的顶点中找出权值最小的顶点,可以看到是V6,所以把V6和V0连接起来。
也就是把V6收录进了这棵最小生成树中了。
接着继续,从当前树中顶点的邻接点中 (也就是V0和V6的邻接点中,找出权值最小的顶点)。可以看到是V1,所以把V1也接入最小生成树中。
然后继续,到V2结点,也接入最小生成树中
因为不能形成回路,
所以V2和V6之间不能连接(虽然权值最小,等于3)。
V0和V1之间也不能连接。所以只能V6和V4连接
最后V4和V5连接,V4再和V3连接,就完成了这棵最小生成树的构建了。
本图为最小生成树的最终模型
好了,基本Prim算法已实现,回归正题
题目传送门
首先,按照做题的方法,我们先把数据全部读入;
然后把两条田地修管子的费用全部求出来,注意本题是无向的;
所以way[i][j]=way[j][i];
还要注意一点,就是如果way[i][j]<c要把way[i][j]设为达到不了 (即设成很大的数)
接着用一个p[]存储当前点有没有用过;
剩下的我给个关键代码吧 (就是Prim算法关键部分):
for(int i=1;i<=n;i++) cnt[i]=way[1][i];
for(int i=1;i<=n-1;i++)
{
int k=0,ji=maxn;
for(int j=1;j<=n;j++) if(cnt[j]<ji&&!p[j]) ji=cnt[j],k=j;
if(ji==maxn){
printf("-1");
return 0;
}
ans+=ji;
p[k]=1;
for(int j=1;j<=n;j++)
if(cnt[j]>way[k][j]&&!p[j]) cnt[j]=way[k][j];
}
最后输出就可以了