最小生成树基础

微笑课本内容小改动~

prim算法:

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#include<algorithm>
#include<iomanip>
#include<cstring>
#include<string>
#include<iostream>
const int MAXN=100+10;
const int INF=999999;
using namespace std;
int G[MAXN][MAXN];
int cp[MAXN];
int dis[MAXN];
int sum;

void prim(int n, int v)
{
    int i,j;
    for(i=0; i<n; i++){
        dis[i]=G[v][i];
        cp[i]=v;
    }
    for(i=1; i<n; i++){
        int min=INF;
        int k=v;
        for(j=0; j<n; j++){
            if(dis[j] && dis[j]<min){
                min=dis[j];
                k=j;
            }
        }
		printf("%d <-> %d = %d\n", cp[k], k, min);//打印两顶点与两点间权值
        sum+=dis[k];//计算最短路径和
        dis[k]=0;//加入集合
        for(j=0; j<n; j++){
            if(G[j][k] && G[j][k]<dis[j]){//更新候选边
                dis[j]=G[j][k];
                cp[j]=k;
            }
        }
    }
    printf("%d\n", sum);
}

int main()
{
    //freopen("in.txt","r",stdin);
    int n,m;
    while(scanf("%d%d", &n,&m), n+m)//节点为0~n-1
    {
        sum=0;
        int i,j;
        for(i=0; i<n; i++){//初始化图
            for(j=0; j<n; j++){
                if(i==j){ G[i][j]=0; continue;}
                G[i][j]=INF;
            }
        }
        for(i=1; i<=m; i++){
            int u,v,w;
            scanf("%d%d%d", &u,&v,&w);
            G[u][v]=w;
            G[v][u]=w;
        }
        prim(n, 0);
    }
    return 0;
}

kruskal算法:

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#include<algorithm>
#include<cstring>
#include<string>
#include<iostream>
const int MAXN=5000+10;
const int INF=99999;
using namespace std;
int fa[101];
int sum;

typedef struct edge
{
    int u,v,w;
}*Edge;

bool cmd(edge e1, edge e2)
{
    return e1.w<e2.w;
}

int find(int x)
{
    if(fa[x]==x) return x;
    return fa[x]=find(fa[x]);
}

void kruskal(int n, Edge E)
{
    int k=1,j=0;
    int u1,v1,c1,c2;
    for(int i=1; i<=n; i++) fa[i]=i;
    while(k<n)//n个点只需要找n-1条边
    {
        u1=E[j].u;
        v1=E[j].v;
        c1=find(u1);
        c2=find(v1);
        if(c1!=c2){//u1与v1属于不同的集合
            fa[c1]=c2;//合并
            k++;
            sum+=E[j].w;
			cout<<u1<<" <-> "<<v1<<" = "<<E[j].w<<endl;//打印方案
        }
        j++;
    }
    printf("%d\n", sum);
}

int main()
{
    freopen("in.txt","r",stdin);
    int n,m;
    while(scanf("%d%d", &n,&m), n+m)
    {
        edge E[MAXN];
        sum=0;
        int i,j;
        j=0;
        for(i=1; i<=m; i++){
            scanf("%d%d%d", &E[j].u,&E[j].v,&E[j].w);
            j++;
        }
        sort(E, E+j, cmd);//按所有边的权值升序排序
        kruskal(n, E);
    }
    return 0;
}

感觉会用并查集的话,kruskal算法比较容易理解。。。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值