问题 J: 算法7-9:最小生成树

题目描述

最小生成树问题是实际生产生活中十分重要的一类问题。假设需要在n个城市之间建立通信联络网,则连通n个城市只需要n-1条线路。这时,自然需要考虑这样一个问题,即如何在最节省经费的前提下建立这个通信网。
可以用连通网来表示n个城市以及n个城市之间可能设置的通信线路,其中网的顶点表示城市,边表示两个城市之间的线路,赋于边的权值表示相应的代价。对于n个顶点的连通网可以建立许多不同的生成树,每一棵生成树都可以是一个通信网。现在,需要选择一棵生成树,使总的耗费最小。这个问题就是构造连通网的最小代价生成树,简称最小生成树。一棵生成树的代价就是树上各边的代价之和。
而在常用的最小生成树构造算法中,普里姆(Prim)算法是一种非常常用的算法。以下是其算法的大致结构:
在本题中,读入一个无向图的邻接矩阵(即数组表示),建立无向图并按照以上描述中的算法建立最小生成树,并输出最小生成树的代价。

输入

输入的第一行包含一个正整数n,表示图中共有n个顶点。其中n不超过50。
以后的n行中每行有n个用空格隔开的整数,对于第i行的第j个整数,如果不为0,则表示第i个顶点和第j个顶点有直接连接且代价为相应的值,0表示没有直接连接。当i和j相等的时候,保证对应的整数为0。
输入保证邻接矩阵为对称矩阵,即输入的图一定是无向图,且保证图中只有一个连通分量。

输出

只有一个整数,即最小生成树的总代价。请注意行尾输出换行。

样例输入复制

4
0 2 4 0
2 0 3 5
4 3 0 1
0 5 1 0

样例输出复制

6

提示

在本题中,需要掌握图的深度优先遍历的方法,并需要掌握无向图的连通性问题的本质。通过求出无向图的连通分量和对应的生成树,应该能够对图的连通性建立更加直观和清晰的概念。

数据结构prim:

#include <iostream>
using namespace std;
const int maxn = 100;
int sum=0;//记录最小花费

typedef struct {
    int vexs[maxn];//顶点数组
    int arcs[maxn][maxn];//邻接矩阵
    int vexnum, arcnum;//顶点数和边数
}MGraph;//图的数据结构

struct {
    int adjvex;//邻接点
    int lowcost;//最短路径权值
}closedge[maxn];//存储最短路径信息

int LocateVex(MGraph G, int v) {//查找顶点v在图G中的位置
    for (int i = 0; i < G.vexnum; i++) {
        if (G.vexs[i] == v) {
            return i;
        }
    }
    return -1;
}
void CreateUDN(MGraph &G) {//创建无向网
    int i, j, k;
    cin>>G.vexnum;//输入顶点数
    for(i=0;i<G.vexnum;i++) G.vexs[i]=i+1;//输入顶点
    for (i = 0; i < G.vexnum; i++) {
        for (j = 0; j < G.vexnum; j++) {
            cin>>G.arcs[i][j];
            if(G.arcs[i][j]==0) G.arcs[i][j]=999;//输入边的权值
        }
    }
}
int Min(MGraph G){//求最小生成树的权值
    int i;
    int index = -1;
    int min = 999;
    for (i = 0; i < G.vexnum; i++)
    {
        if (closedge[i].lowcost < min && closedge[i].lowcost != 0)
        {
            min = closedge[i].lowcost;
            index = i;
        }
    }
    return index;
}
void Prim(MGraph G,int u)
{
    int i,j,k;
    int v1, v2;
    k= LocateVex(G,u);
    for(j=0;j<G.vexnum;j++)
    {
        if(j!=k)
        {//初始化
            closedge[j].adjvex=u;
            closedge[j].lowcost=G.arcs[k][j];
        }
    }
    closedge[k].lowcost=0;
    for ( i=1;i<G.vexnum;i++)
    {
        k=Min(G);//求最小生成树的权值
        sum+=closedge[k].lowcost;
        closedge[k].lowcost=0;
        for( j=0;j<G.vexnum;j++)
        {
            if(G.arcs[k][j]<closedge[j].lowcost)
            {//更新
                closedge[j].adjvex=G.vexs[k];
                closedge[j].lowcost=G.arcs[k][j];
            }
        }
    }
}
int main()
{
    MGraph G;
    CreateUDN(G);
    Prim(G,1);
    cout<<sum<<endl;
    return 0;
}

并查集:

#include <iostream>
#include <algorithm>

using namespace std;
const int maxn = 50 + 5;

int n, k = 1;
int F[maxn];

struct Edge
{
    int x, y, w;
    bool operator<(const Edge &e) const
    {
        return w < e.w;
    }
} edge[maxn*maxn];

void Init()
{
    cin >> n;
    for (int i = 1; i <= n; i++) F[i] = i;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
        {//将邻接矩阵转化为边集
            int temp;cin >> temp;
            if (i == j || temp == 0) continue;
            edge[k++] = {i, j, temp};
        }
    sort(edge + 1, edge + k + 1);
}

int Find(int x)
{
    return x == F[x] ? x : F[x] = Find(F[x]);
}

bool Union(int x, int y)
{
    int fx = Find(x);
    int fy = Find(y);
    if (fx == fy) return false;//不用合并,xy已经在一棵树上了
    F[fy] = fx;//把fy所在的子树都合并到fx这个树上 fx是合并后的树根
    return true;
}

int main()
{
    int total = 0;
    Init();
    for (int i = 1; i < k; i++)
    {
        if (Union(edge[i].x, edge[i].y))
        {
            total += edge[i].w;
        }
    }
    cout << total << endl;
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

VICTOR.杰

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

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

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

打赏作者

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

抵扣说明:

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

余额充值