[数据结构] DS图—最小生成树

题目描述
根据输入创建无向网。分别用Prim算法和Kruskal算法构建最小生成树。(假设:输入数据的最小生成树唯一。)

输入
顶点数n
n个顶点
边数m
m条边信息,格式为:顶点1 顶点2 权值
Prim算法的起点v

输出
输出最小生成树的权值之和

对两种算法,按树的生长顺序,输出边信息(Kruskal中边顶点按数组序号升序输出)

样例输入
6
v1 v2 v3 v4 v5 v6
10
v1 v2 6
v1 v3 1
v1 v4 5
v2 v3 5
v2 v5 3
v3 v4 5
v3 v5 6
v3 v6 4
v4 v6 2
v5 v6 6
v1
样例输出
15
prim:
v1 v3 1
v3 v6 4
v6 v4 2
v3 v2 5
v2 v5 3
kruskal:
v1 v3 1
v4 v6 2
v2 v5 3
v3 v6 4
v2 v3 5

参考代码

#include <iostream>

using namespace std;

#define MAX_WEIGHT 99999

struct
{
    string adjvex;
    int weight;
} Close_Edge[100]; //该点周围权值最小的边

class MGraph
{
public:
    int Graph_Prim[100][100], Graph_Kruskal[100][100]; //图的权值矩阵
    int n, nedge; //n是节点个数,len是边个数
    int visited[100]; //Prim中标记已连接的点
    string *node; //存放节点名
    string start; //Prim开始节点
    int startpos; //Prim开始位置
    MGraph() {}
    void SetMGraph();
    void Prim();
    void Kruskal();
};

void MGraph::SetMGraph() //数值输入及初始化
{
    int i, j;
    cin>>n;
    for(i=0; i<n; i++)
    {
        for(j=0; j<n; j++)
        {
            Graph_Prim[i][j] = 10000;
            Graph_Kruskal[i][j] = 10000;
        }
    }

    node = new string[n];
    for(i=0; i<n; i++)
        cin>>node[i];

    cin>>nedge;
    for(i=1; i<=nedge; i++)
    {
        string ch1, ch2;
        int weight_;
        cin>>ch1>>ch2>>weight_;
        int loc1, loc2;
        for(j=0; j<n; j++)
        {
            if(node[j]==ch1)
                loc1 = j;
            if(node[j]==ch2)
                loc2 = j;
        }
        //构建权值矩阵
        Graph_Kruskal[loc1][loc2] = Graph_Prim[loc1][loc2] = weight_;
        Graph_Kruskal[loc1][loc2] = Graph_Prim[loc2][loc1] = weight_;
        /*Graph_Prim[loc1][loc2] = weight_;
        Graph_Prim[loc2][loc1] = weight_;
        Graph_Kruskal[loc1][loc2] = weight_;
        Graph_Kruskal[loc2][loc1] = weight_;*/
    }
    cin>>start;
    for(i=0; i<n; i++) //确定Prim开始位置
        if(node[i]==start)
            startpos = i;
}

void MGraph::Prim()
{
    int i, j;
    for(i=1; i<=n; i++)
        visited[i] = 0;
    visited[startpos] = 1;
    int min_;

    //找出每个点周围权值最小的边及其邻接的点
    for(i=0; i<n; i++)
    {
        min_ = MAX_WEIGHT;
        for(j=0; j<n; j++)
        {
            if(Graph_Prim[i][j]<min_)
            {
                min_ = Graph_Prim[i][j];
                Close_Edge[i].adjvex = node[j];
                Close_Edge[i].weight = min_;
            }
        }
    }

    string s3;
    string *e1,*e2;
    int *w3;
    e1=new string[100];
    e2=new string[100];
    w3=new int[100];

    int index, k=0;
    for(i=0; i<n; i++) //这里可能要修改为从起始点start开始
    {
        min_ = MAX_WEIGHT;
        for(j=0; j<n; j++)
        {
            if(!visited[j])
                continue;
            else
            {
                if(min_>Close_Edge[j].weight)
                {
                    min_ = Close_Edge[j].weight;
                    s3 = Close_Edge[j].adjvex;
                    index = j;
                }
            }
        }
        e1[k] = node[index];
        e2[k] = s3; w3[k++] = min_;

        for(int g=0; g<n; g++) //标记已连接的点
        {
            if(node[g]==s3)
            {
                visited[g] = 1;
                break;
            }
        }
        for(int g=0; g<n; g++) //更新Close_Edge
        {
            min_ = MAX_WEIGHT;
            for(int m=0; m<n; m++)
            {
                if(min_>Graph_Prim[g][m] && visited[m]==0)
                {
                    min_ = Graph_Prim[g][m];
                    Close_Edge[g].adjvex=node[m];
                    Close_Edge[g].weight=min_;
                }
            }
        }
    }
    int Weight=0;
    for(i=0; i<k-1; i++)
    {
        Weight+=w3[i];
    }
    cout<<Weight<<endl;
    cout<<"prim:"<<endl;
    for(i=0; i<k-1; i++)
        cout<<e1[i]<<" "<<e2[i]<<" "<<w3[i]<<endl;
}

void MGraph::Kruskal()
{
    cout<<"kruskal:"<<endl;
    int *uni = new int[n];

    //标记哪些点相连,uni值相同表示这些点在一个连通分量内
    for(int i=0; i<n; i++)
        uni[i] = i;

    for(int i=0; i<n-1; i++)
    {
        int min=MAX_WEIGHT;
        int x, y;
        for(int j=0; j<n; j++) //找出权值最小的边
        {
            for(int k=0; k<n; k++)
            {
                if(j==k)
                    continue;
                if(uni[j]==uni[k])
                    continue;
                else
                {
                    if(min>Graph_Kruskal[j][k])
                    {
                        min = Graph_Kruskal[j][k];
                        x=j; y=k;
                    }
                }
            }
        }
        Graph_Kruskal[x][y] = MAX_WEIGHT;
        Graph_Kruskal[y][x] = MAX_WEIGHT;

        if(x>y) //确保最后升序输出,x要小于y
            swap(x, y);

        for(int i=0; i<n; i++)
        {
            if(uni[i]==uni[y] && i!=y) //如果点y已经在包含多个点的连通分量内
                uni[i] = uni[x];
        }
        uni[y] = uni[x];
        cout<<node[x]<<" "<<node[y]<<" "<<min<<endl;
    }
}

int main()
{
    MGraph m,M;
    m.SetMGraph();
    m.Prim();
    m.Kruskal();
    return 0;
}
  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 1024 设计师:白松林 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值