最短网络-

最短网络


题目描述

https://cdn.jsdelivr.net/gh//3CodeLove/Images@main/20210724102626.png


核心思路

从题意可知,农夫想要连接所有农场并且想要所使用的光纤最短。这其实就是想要求最小生成树,因为最小生成树一定包含所有节点(即所有农场),而且是连通的(连接所有农场),并且边权之和是最小的(所使用的光纤最短)。因此就是一道裸的最小生成树算法。

求解最小生成树有两种算法:prim算法和Kruskal算法。

  • prim算法一般适用于稠密图,用邻接矩阵存储。而题目又说了对称矩阵,所以这题就可以用prim算法来求解
  • Kruskal算法一般适用于稀疏图,我们一般用结构体来存储

代码

写法1:

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=110,INF=0x3f3f3f3f;
int n;
//prim算法比较适用于稠密图  稠密图可以用邻居矩阵来存储
//这里采用prim算法  所以用了邻居矩阵
int g[N][N];
//dist[i]表示节点i距离S集合的距离
int dist[N];
//st[i]=true表示节点i已经被加入了S集合
bool st[N];
//prim算法求最小生成树
int prim()
{
    int res=0;  //最小生成树的权值总和
    memset(dist,0x3f,sizeof dist);  //距离初始化为无穷大
    //起点1号节点到自身距离为0
    dist[1]=0;
    //最终得到的最小生成树中一定有n个节点
    //因此需要循环n次  每个把一个节点加入S集合中
    //最终都会把这n个节点加入S集合中
    for(int i=0;i<n;i++)
    {
        int t=-1;   //寻找不在S集合中,但是距离S集合最近的一个节点
        for(int j=1;j<=n;j++)
            if(!st[j]&&(t==-1||dist[t]>dist[j]))
                t=j;
        if(dist[t]==INF)
            return INF;
        res+=dist[t];   //累加最小生成树的权值和
        st[t]=true;   //标记节点t已经被加入了S集合
        //遍历节点t的所有邻接点  通过t来更新这些邻接点到起点的距离
        for(int k=1;k<=n;k++)
            if(!st[k])
                dist[k]=min(dist[k],g[t][k]);
    }
    return res;
}
int main()
{
    scanf("%d",&n);
    //读入邻接矩阵
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            scanf("%d",&g[i][j]);
    printf("%d\n",prim());
    return 0;
}

写法2:

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=110,INF=0x3f3f3f3f;
int n;
int g[N][N];
int dist[N];
bool st[N];
int prim()
{
    int res=0;
    memset(dist,0x3f,sizeof dist);
    for(int i=0;i<n;i++)
    {
        int t=-1;
        for(int j=1;j<=n;j++)
            if(!st[j]&&(t==-1||dist[t]>dist[j]))
                t=j;
        if(i&&dist[t]==INF)
            return INF;
        if(i)
            res+=dist[t];
        st[t]=true;
        for(int k=1;k<=n;k++)
            dist[k]=min(dist[k],g[t][k]);
    }
    return res;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            scanf("%d",&g[i][j]);
    printf("%d\n",prim());
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

卷心菜不卷Iris

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值