最小生成树

//HDU 1836
//最小生成树 prime
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<set>
using namespace std ;


const int maxn = 1e2 + 10 ;
const int INF = 0x3f3f3f3f ;

bool vis[maxn] ;
int lowc[maxn] ;
int cost[maxn][maxn] ;

    //prime算法思想:将节点分为已经访问的集合和未访问的集合,不断从未访问集合里面找到一个距离已经访问过的集合最近的点访问
int prime(int n ){
    int ans = 0 ;
    memset( vis , false , sizeof( vis )) ;

    //设置1为初始访问点 
    vis[1] = true ;
    //未访问节点和已经访问节点集合的最近距离
    for(int i = 2 ;i<=n ; i ++)
        lowc[i] = cost[1][i] ;
    //未访问节点由n-1个,选择n-1个节点放入已经访问集合中
    for(int i = 2; i<=n ;i++){
        int minc = INF ;
        int p = -1 ;
        //在未访问节点中选择距离已经访问的集合中距离最近的一个节点访问,注意对距离集合最近的理解:在每次添加一个节点到已经访问的节点集合的时候,这个点所连接的所有的边就连接这个已经访问的集合,那么我们下一次要找的距离已经访问的节点集合最近的点就在这些连接 已经访问的节点集合的边的未进入已经访问的节点集合的其他端点里面找了
        for( int j = 1 ;j<=n ;j++)
            //在已经访问的节点集合所连接的边的未访问节点中找一个距离已经节点集合距离最近的点,注意lowc存储的是距离未访问的节点到已经访问的节点集合的距离 
            if( !vis[j] && minc > lowc[j]){
                minc = lowc[j] ;
                p = j ;
            } 
        //原图不连通,注意到外循环是要找n-1个点,如果程序跑到这一步,则说明还没有找到n-1个点,但是在找一个点的时候我们没有找到他,他满足到已经访问的节点集合不为INF,为INF表示不存在和已经访问的节点集合连通的点,也就是这个图是不连通的
        if( minc == INF )
            return -1 ;

        ans += minc ;
        //添加到已经访问的节点集合中 
        vis[p] = true ; 

        for(int j = 1 ;j<=n ; j++)
            //因为我们已经添加了一个点p,那么和p相连的边和就和已经访问的节点集合相连,而边的端点可能是未访问的节点,而这个节点因为p的原因,他到已经访问的节点集合的距离就可能变小,所以需要松弛 
            if( !vis[j] && lowc[j] > cost[p][j] )
                //松弛变小 
                lowc[j] = cost[p][j] ;
    } 
    return ans ; 
}

void ini(){
    for(int i = 0 ;i<maxn ;i++){
        for(int j = 0 ;j<maxn ;j++)
            cost[i][j] = INF ;
    }
}

int main(){
    int a , b ;
    while( cin>>a>> b && a){

        ini() ;

        int c , d , e ;
        for(int i = 0 ;i< a ;i++){
            cin>>c >>d >>e ;
            cost[c][d] = e ;
            cost[d][c] = e ;
        }

        int ans = prime(b) ;

        if( ans != -1)
            printf("%d\n" , ans) ;
        else
            printf("?\n") ;
    }
    return 0 ;
} 
//最小生成树 kruskal
#include<iostream>
#include<cstdio>
#include<sstream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<deque>
#include<stack>
using namespace std;
#define unsigned long long ll;
const int maxn=1e4;
int f[100+5];
int F(int x){
    return x==f[x]?x:f[x]=F(f[x]);
}
struct T{
    int a,b,c;
}p[maxn];
bool cmp(T a,T b){
    return a.c<b.c;
}
int main(){
    int T,a,b,c;
    while(cin>>T&&T){
        for(int i=1;i<=T;i++)f[i]=i;
        int N=T*(T-1)/2; 
        for(int i=0;i<N;i++)
            scanf("%d%d%d",&p[i].a,&p[i].b,&p[i].c);
        sort(p,p+N,cmp);
        int cnt=0;
        for(int i=0;i<N;i++){
            int x=F(p[i].a);
            int y=F(p[i].b);
            if(x!=y){
                cnt+=p[i].c;
                f[x]=y;
            }
        }
        printf("%d\n",cnt);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值