贪心——无向图最小生成树

题目链接:

        https://www.51nod.com/Challenge/Problem.html#problemId=1212


题解:

         个人认为本题的题眼在于,将该连通图构成一个二维数组,每两个联通的点为该数组的横纵两坐标值。由于该图为无向图那么如:fan[a][b] 和 fan[b][a]两个地方的权值应该是相等的,也就是说a-b和b-a这两边因为无向,所以这两点之间公用一条道路。

        首先,我们先了解一下什么是最小生成树?

         最小生成树在连通网的所有生成树中,所有边的代价和最小的生成树,称为最小生成树。 
这里写图片描述

        通过我们学的数据结构可知求出最小生成树有两种方法:

1.Kruskal算法

       此算法可以称为“加边法”,初始最小生成树边数为0,每迭代一次就选择一条满足条件的最小代价边,加入到最小生成树的边集合里。

2.Prim算法

         此算法可以称为“加点法”,每次迭代选择代价最小的边对应的点,加入到最小生成树中。算法从某一个顶点s开始,逐渐长大覆盖整个连通网的所有顶点。

 本题中我用了第二种方法来实现的代码,如下:

#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
int min;int n,m;
int fan[10005][10005];
int vis[10005],low[10005]; 
int ss(){
	int min,pos,sum=0;
	memset(vis,0,sizeof(vis));
	pos=1;
	vis[1]=1;
	for(int i=1;i<=n;i++){  
		if(i!=pos)
		low[i]=fan[pos][i];  //此时的low[i]中找到了从点1开始到其他能联通边的权值 
	}
	for(int i=1;i<n;i++){  //共n-1条边相加 
	    min=9999999;    
        for(int j=1;j<=n;j++){ 
		   //按权值从小到大的顺序找边 
          	 if(!vis[j]&&low[j]<min){
		//如果这个点没有被联通
		       min=low[j];
			   pos=j; 
		      }
       }
    	sum+=min;  //将权值大小依次相加。
		vis[pos]=1;//标记一下表示此点已经和点1联通 
		for(int j=1;j<=n;j++){
			//此时为找到和上一个点已经连通过的点,它和它能联通的点的边的权值 
			if(!vis[j]&&low[j]>fan[pos][j]){
				low[j]=fan[pos][j];
			} 
		} 
   }
   return sum;
}
int main(){
	while(cin>>n>>m){
		int a,b,c;
	memset(fan,999999,sizeof(fan));
	for(int i=1;i<=m;i++){
		cin>>a>>b>>c;
		if(fan[a][b]>c) {
		    //防重边 
	     	fan[a][b]=c;
	    	fan[b][a]=c; 
		}
	}
	cout<<ss()<<endl;
	}
	
	return 0;
}

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值