五、图的应用

1.实验目的

(1)掌握图的相关概念,包括图、有向图、无向图、子图、连通图、度、入度、出度、简单回路、环等;

(2)掌握图的各种存储结构,包括邻接矩阵和邻接表等;

(3)掌握图的基本运算,包括创建图、输出图、深度优先遍历、广度优先遍历等;

(4)掌握图的其他运算,包括最小生成树、最短路径、拓扑排序和关键路径等算法。

2.实验内容

利用Prim算法求网的最小生成树。

要求和提示:设图的顶点数为10个。为简单起见,网中边的权值设成小于100的整数,可利用C语言的rand()函数产生。

3.源程序和实验结果

#include <iostream>

#include <string>

#include <iomanip>

#include <cstdlib>

#define INT_max 100000 //借此表示无穷大

#define Num 10         //表示顶点个数 10个顶点

using namespace std;

struct Graph

{

    int vexnum;   //顶点个数

    int arcnum;   //边的条数

    int **arcs;   //邻接矩阵

    string *vexs; //顶点向量

};

typedef struct

{

    string adjvex; //该边依附在U中的顶点

    int lowcost;   //存储该边上的权

} closedge;

 

void createGraph(Graph &g); // 创建图

 

void print(Graph g); // 打印图

 

void miniSpanTree_PRIM(Graph g, string u); //普利姆算法求最小生成树

 

int locateVex(Graph g, string u); //确定顶点u在图g中位置

 

int minimum(closedge *closedge); //求T的下一个结点

int main()

{

    Graph g;

    createGraph(g);

    cout << "构造好后图的邻接矩阵为:" << endl;

    print(g);

    int start = 0; //从编号为start的顶点开始

    miniSpanTree_PRIM(g, g.vexs[start]);

    return 0;

}

 

void createGraph(Graph &g)

{

    g.vexnum = Num; //顶点数目为10

    cout << "输入边的条数" << endl;

    cin >> g.arcnum;

 

    g.vexs = new string[g.vexnum];

    g.arcs = new int *[g.vexnum];

 

    // 初始化

    for (int i = 0; i < g.vexnum; i++)

    {

        g.vexs[i] = "v" + std::to_string(i); //对每个顶点进行命名

        g.arcs[i] = new int[g.vexnum];

        for (int j = 0; j < g.vexnum; j++)

            g.arcs[i][j] = INT_max;

    }

 

    cout << "请输入每条边的顶点编号(0-9),权值由随机函数生成(1-100)" << endl;

    srand(1); //随机种子,保证每次随机数相同

    for (int i = 0; i < g.arcnum; i++)

    {

        int start, end, weight;

        cin >> start >> end;

        weight = rand() % 99 + 1;

        g.arcs[start][end] = weight;

        g.arcs[end][start] = weight;

    }

}

 

void print(Graph g)

{

    for (int i = 0; i < g.vexnum; i++)

    {

        for (int j = 0; j < g.vexnum; j++)

        {

            if (g.arcs[i][j] == INT_max)

                cout << left << setw(6) << "";

 

            else

                cout << left << setw(6) << g.arcs[i][j];

        }

        cout << endl;

    }

}

 

void miniSpanTree_PRIM(Graph g, string u)

{

    //用普利姆算法从第u个顶点出发构造网g的最小生成树T,输出T的各条边。

    //记录从顶点集U到V-U的代价最小的边的辅助数组定义:

    closedge closedge[g.vexnum];

    int k = locateVex(g, u);

    //辅助数组初始化

    for (int j = 0; j < g.vexnum; j++)

        if (j != k)

            closedge[j] = {u, g.arcs[k][j]};

    closedge[k].lowcost = 0;

 

    for (int i = 1; i < g.vexnum; i++) //选择其余g.vexnum-1个顶点

    {

        k = minimum(closedge); //求出T的下一个结点:第k结点

        cout << closedge[k].adjvex << "------->" << g.vexs[k] << "        权值为:" << closedge[k].lowcost << endl;

        closedge[k].lowcost = 0; //第k顶点并入U集

 

        for (int j = 0; j < g.vexnum; j++) //新顶点并入U后重新选择最小边

            if (g.arcs[k][j] < closedge[j].lowcost)

                closedge[j] = {g.vexs[k], g.arcs[k][j]};

    }

}

 

int locateVex(Graph g, string u)

{

    int i;

    for (i = 0; i < g.vexnum; i++)

    {

        if (g.vexs[i] == u)

            return i;

    }

    if (i == g.vexnum)

    {

        cout << "该顶点不在图中..." << endl;

    }

    return -1;

}

 

int minimum(closedge *closedge)

{

    int i, min, k;

    for (i = 0, min = INT_max; i < Num; i++)

    {

        if (closedge[i].lowcost > 0 && closedge[i].lowcost < min)

        {

            min = closedge[i].lowcost;

            k = i;

        }

    }

    return k;

}

 

 

测试数据:

16

0 1

0 4

0 5

0 9

1 2

1 6

1 9

2 4

2 8

3 6

3 7

3 9

4 7

5 8

6 9

7 8

构造出来的无向网:

输出结果截图:

 

4.分析与讨论

如何使用邻接矩阵构造无向网

如何使用prim算法构造最小生成树

 

posted @ 2021-11-22 22:23  请去看诡秘之主  阅读(47)  评论(0编辑  收藏  举报