• 最小生成树、最短路径


    最小生成树:

    普里姆算法 和 克鲁斯卡尔算法

    普里姆算法:归并顶点,适用稠密网。

    克鲁斯卡尔算法:归并边,适用稀疏网。

    /******* 普里姆算法(最小生成树) *********/void MiniSpanTree_Prim(AMGraph G, VerTexType u)//最小生成树 普利姆
    {
        int i, j, k;
        VerTexType u0, v0;
        k = LocateVex(G, u);
        for (j = 0; j < G.vexnum; ++j)
            if (j != k)
                closedge[j] = { u,G.arcs[k][j] };
        closedge[k].lowcost = 0;
        for (i = 1; i < G.vexnum; ++i)
        {
            k = Min(G);
            u0 = closedge[k].adjvex;
            v0 = G.vexs[k];
            cout << u0 <<"--"<< v0<<"  ";
            closedge[k].lowcost = 0;
            for (j = 0; j < G.vexnum; j++)
                if (G.arcs[k][j] < closedge[j].lowcost)
                    closedge[j] = { G.vexs[k],G.arcs[k][j] };
        }
    }
    
    
    /**************克鲁斯卡尔算法 (最小生成树)************/
    void MiniSpanTree_Kruskal(AMGraph G) 
    {    
        int i, j, v1, v2, vs1, vs2;
        Sort(G);                                             
        for (i = 0; i < G.vexnum; ++i)                         
            Vexset[i] = i;
        for (i = 0; i < G.arcnum; ++i) { 
            v1 = LocateVex(G, Edge[i].Head);                 
            v2 = LocateVex(G, Edge[i].Tail);                 
            vs1 = Vexset[v1];                                
            vs2 = Vexset[v2];                               
            if (vs1 != vs2) {                                 
                cout << Edge[i].Head << "--" << Edge[i].Tail <<"  ";    
                for (j = 0; j < G.vexnum; ++j)              
                    if (Vexset[j] == vs2) Vexset[j] = vs1;    
            } 
        }
    }

    最短路径:

    迪杰特斯拉算法和弗洛伊德算法

    /**************迪杰特斯拉算法*******************/
    void ShortestPath_DIJ(AMGraph G, int v0) {
        //用Dijkstra算法求有向网G的v0顶点到其余顶点的最短路径 
        int v, i, w, min;
        int n = G.vexnum;                                        //n为G中顶点的个数 
    
        for (v = 0; v < n; ++v) {                                 //n个顶点依次初始化 
            S[v] = false;                                          //S初始为空集 
            D[v] = G.arcs[v0][v];                               //将v0到各个终点的最短路径长度初始化为弧上的权值 
            if (D[v] < MaxInt)  Path[v] = v0;                      //如果v0和v之间有弧,则将v的前驱置为v0 
            else Path[v] = -1;                                   //如果v0和v之间无弧,则将v的前驱置为-1 
        }//for 
    
        S[v0] = true;                                                //将v0加入S 
        D[v0] = 0;                                                  //源点到源点的距离为0 
    
                                                                    /*―初始化结束,开始主循环,每次求得v0到某个顶点v的最短路径,将v加到S集―*/
        for (i = 1; i < n; ++i) {                                    //对其余n-1个顶点,依次进行计算 
            min = MaxInt;
            for (w = 0; w < n; ++w)
                if (!S[w] && D[w] < min) {                        //选择一条当前的最短路径,终点为v 
                    v = w;
                    min = D[w];
                }//if             
            S[v] = true;                                           //将v加入S 
            for (w = 0; w < n; ++w)                               //更新从v0出发到集合V?S上所有顶点的最短路径长度 
                if (!S[w] && (D[v] + G.arcs[v][w] < D[w])) {
                    D[w] = D[v] + G.arcs[v][w];                   //更新D[w] 
                    Path[w] = v;                                  //更改w的前驱为v 
                }//if 
        }//for  
    }//ShortestPath_DIJ

    弗洛伊德算法:

    void ShortestPath_Floyed(AMGraph G){ 
        //用Floyd算法求有向网G中各对顶点i和j之间的最短路径 
        int i , j , k ;
        for (i = 0; i < G.vexnum; ++i)                  //各对结点之间初始已知路径及距离 
            for(j = 0; j < G.vexnum; ++j){ 
                D[i][j] = G.arcs[i][j]; 
                if(D[i][j] < MaxInt && i != j)  Path[i][j]=i;      //如果i和j之间有弧,则将j的前驱置为i 
                else Path [i][j] = -1;                      //如果i和j之间无弧,则将j的前驱置为-1 
            }//for
            for(k = 0; k < G.vexnum; ++k) 
                for(i = 0; i < G.vexnum; ++i) 
                    for(j = 0; j < G.vexnum; ++j)
                        if(D[i][k] + D[k][j] < D[i][j]){           //从i经k到j的一条路径更短 
                            D[i][j] = D[i][k]+D[k][j];            //更新D[i][j] 
                            Path[i][j] = Path[k][j];                   //更改j的前驱为k 
                        }//if 
    }//ShortestPath_Floyed

    我的作业:

    #include <iostream>
    using namespace std;
    
    #define OK 1
    #define MaxInt 32767
    #define MVNum 100
    typedef int Status;
    typedef char VerTexType;
    typedef int ArcType;
    int visited[MVNum] = { 0 };
    
    typedef struct
    {
        VerTexType vexs[MVNum];
        ArcType arcs[MVNum][MVNum];
        int vexnum, arcnum;
    }AMGraph;
    
    int LocateVex(AMGraph G, VerTexType u)
    {
        int i;
        for (i = 0; i < G.vexnum; ++i)
            if (u == G.vexs[i])
                return i;
        return -1;
    }
    
    void DFS_AM(AMGraph G, int v)//深度遍历
    {
        cout << G.vexs[v];
        visited[v] = 1;
        for (int w = 0; w < G.vexnum; ++w)
            if ((G.arcs[v][w] != 0) && (!visited[w]))
            {
                DFS_AM(G, w);
            }
    }
    
    void DrawLine(int n)
    {
        printf("
    --+");
        for (int i = 0; i < n; ++i)
        {
            printf("------+");
        }
        printf("
    ");
    }
    
    void Display_AM(AMGraph G)
    {
        for (int i = 0; i < G.vexnum; ++i)
            printf("%7c", G.vexs[i]);
        DrawLine(G.vexnum);
        for (int i = 0; i < G.vexnum; ++i)
        {
            printf(" %c|", G.vexs[i]);
            for (int j = 0; j < G.vexnum; ++j)
            {
                printf("%6d|", G.arcs[i][j]);
            }
            DrawLine(G.vexnum);
        }
    }
    
    /******* 普里姆算法(最小生成树) *********/
    struct 
    {
        VerTexType adjvex;
        ArcType lowcost;
    }closedge[MVNum];
    
    Status CreateUDN(AMGraph &G)//构造无向网
    {
        int i, j, k;
        cout << "请输入总顶点数,总边数,以空格隔开:";
        cin >> G.vexnum >> G.arcnum;
        cout << endl;
    
        cout << "输入点的名称:";
    
        for (i = 0; i < G.vexnum; ++i) {
            cin >> G.vexs[i];
        }
        cout << endl;
        for (i = 0; i < G.vexnum; ++i)
            for (j = 0; j < G.vexnum; ++j)
                G.arcs[i][j] = MaxInt;
        for (k = 0; k < G.arcnum; ++k) {
            VerTexType v1, v2;
            ArcType w;
            cout << "请输入第" << (k + 1) << "条边及权值:";
            cin >> v1 >> v2 >> w;
            i = LocateVex(G, v1);  j = LocateVex(G, v2);
            G.arcs[i][j] = w;
            G.arcs[j][i] = G.arcs[i][j];
        }
        return OK;
    }
    
    
    int Min(AMGraph G)
    {
        int i;
        int index = -1;
        int min = MaxInt;
        for (i = 0; i < G.vexnum; ++i) {
            if (min > closedge[i].lowcost && closedge[i].lowcost != 0) {
                min = closedge[i].lowcost;
                index = i;
            }
        }
        return index;
    }
    
    void MiniSpanTree_Prim(AMGraph G, VerTexType u)//最小生成树 普利姆
    {
        int i, j, k;
        VerTexType u0, v0;
        k = LocateVex(G, u);
        for (j = 0; j < G.vexnum; ++j)
            if (j != k)
                closedge[j] = { u,G.arcs[k][j] };
        closedge[k].lowcost = 0;
        for (i = 1; i < G.vexnum; ++i)
        {
            k = Min(G);
            u0 = closedge[k].adjvex;
            v0 = G.vexs[k];
            cout << u0 <<"--"<< v0<<"  ";
            closedge[k].lowcost = 0;
            for (j = 0; j < G.vexnum; j++)
                if (G.arcs[k][j] < closedge[j].lowcost)
                    closedge[j] = { G.vexs[k],G.arcs[k][j] };
        }
    }
    
    /**************克鲁斯卡尔算法 (最小生成树)************/
    
    struct
    {
        VerTexType Head;
        VerTexType Tail;
        ArcType lowcost;
    }Edge[MVNum];
    
    int Vexset[MVNum];
    
    Status CreateUDN_Kruskal(AMGraph &G)
    {
        int i, j, k;
        cout << "请输入总顶点数,总边数,以空格隔开:";
        cin >> G.vexnum >> G.arcnum;
        cout << endl;
    
        cout << "输入点的名称:";
    
        for (i = 0; i < G.vexnum; ++i) {
            cin >> G.vexs[i];
        }
        cout << endl;
        for (i = 0; i < G.vexnum; ++i)
            for (j = 0; j < G.vexnum; ++j)
                G.arcs[i][j] = MaxInt;
        for (k = 0; k < G.arcnum; ++k) {
            VerTexType v1, v2;
            ArcType w;
            cout << "请输入第" << (k + 1) << "条边及权值:";
            cin >> v1 >> v2 >> w;
            i = LocateVex(G, v1);  j = LocateVex(G, v2);
            G.arcs[i][j] = w;
            G.arcs[j][i] = G.arcs[i][j];
            Edge[k].lowcost = w;
            Edge[k].Head = v1;
            Edge[k].Tail = v2;
        }
        return OK;
    }
    
    void Sort(AMGraph G)//冒泡排序 
    {
        int m = G.arcnum - 2;
        int flag = 1;
        while ((m > 0) && flag == 1) {
            flag = 0;
            for (int j = 0; j <= m; j++) {
                if (Edge[j].lowcost > Edge[j + 1].lowcost) {
                    flag = 1;
    
                    VerTexType temp_Head = Edge[j].Head;
                    Edge[j].Head = Edge[j + 1].Head;
                    Edge[j + 1].Head = temp_Head;
    
    
                    VerTexType temp_Tail = Edge[j].Tail;
                    Edge[j].Tail = Edge[j + 1].Tail;
                    Edge[j + 1].Tail = temp_Tail;
    
                    ArcType temp_lowcost = Edge[j].lowcost;
                    Edge[j].lowcost = Edge[j + 1].lowcost;
                    Edge[j + 1].lowcost = temp_lowcost;
                }
            }
            --m;
        }
    }
    
    void MiniSpanTree_Kruskal(AMGraph G) 
    {    
        int i, j, v1, v2, vs1, vs2;
        Sort(G);                                             
        for (i = 0; i < G.vexnum; ++i)                         
            Vexset[i] = i;
        for (i = 0; i < G.arcnum; ++i) { 
            v1 = LocateVex(G, Edge[i].Head);                 
            v2 = LocateVex(G, Edge[i].Tail);                 
            vs1 = Vexset[v1];                                
            vs2 = Vexset[v2];                               
            if (vs1 != vs2) {                                 
                cout << Edge[i].Head << "--" << Edge[i].Tail <<"  ";    
                for (j = 0; j < G.vexnum; ++j)              
                    if (Vexset[j] == vs2) Vexset[j] = vs1;    
            } 
        }
    }
    
    
    /**************迪杰特斯拉算法*******************/
    
    void ShortestPath_DIJ(AMGraph G, int v0) {
        //用Dijkstra算法求有向网G的v0顶点到其余顶点的最短路径 
        int v, i, w, min;
        int n = G.vexnum;                                        //n为G中顶点的个数 
    
        for (v = 0; v < n; ++v) {                                 //n个顶点依次初始化 
            S[v] = false;                                          //S初始为空集 
            D[v] = G.arcs[v0][v];                               //将v0到各个终点的最短路径长度初始化为弧上的权值 
            if (D[v] < MaxInt)  Path[v] = v0;                      //如果v0和v之间有弧,则将v的前驱置为v0 
            else Path[v] = -1;                                   //如果v0和v之间无弧,则将v的前驱置为-1 
        }//for 
    
        S[v0] = true;                                                //将v0加入S 
        D[v0] = 0;                                                  //源点到源点的距离为0 
    
                                                                    /*―初始化结束,开始主循环,每次求得v0到某个顶点v的最短路径,将v加到S集―*/
        for (i = 1; i < n; ++i) {                                    //对其余n-1个顶点,依次进行计算 
            min = MaxInt;
            for (w = 0; w < n; ++w)
                if (!S[w] && D[w] < min) {                        //选择一条当前的最短路径,终点为v 
                    v = w;
                    min = D[w];
                }//if             
            S[v] = true;                                           //将v加入S 
            for (w = 0; w < n; ++w)                               //更新从v0出发到集合V?S上所有顶点的最短路径长度 
                if (!S[w] && (D[v] + G.arcs[v][w] < D[w])) {
                    D[w] = D[v] + G.arcs[v][w];                   //更新D[w] 
                    Path[w] = v;                                  //更改w的前驱为v 
                }//if 
        }//for  
    }//ShortestPath_DIJ
    
    void DisplayPath(AMGraph G, int begin, int temp) {
        //显示最短路
        if (Path[temp] != -1) {
            DisplayPath(G, begin, Path[temp]);
            cout << G.vexs[Path[temp]] << "-->";
        }
    }

    测试:

    int main()
    {
        cout << "以邻接矩阵形式存储无向网,遍历连通图并构造最小生成树。" << endl;
        AMGraph G;
        cout << "
    请选择(最小生成树) :(1)普里姆  (2)克鲁斯卡尔" << endl;
        int a;
        cin >> a;
        if (a == 1)
        {
            CreateUDN(G);
            cout << "
    邻接矩阵为:" << endl;
            Display_AM(G);
            cout << "
    遍历结果:";
            DFS_AM(G, 0);
            cout << endl;
            VerTexType u;
            cout << "
    输入源点:";
            cin >> u;
            cout << "
    最小生成树(普里姆):";
            MiniSpanTree_Prim(G, u);
        }
        else if (a == 2)
        {
            CreateUDN_Kruskal(G);
            cout << "
    邻接矩阵为:" << endl;
            Display_AM(G);
            cout << "
    遍历结果:";
            DFS_AM(G, 0);
            cout << endl;
            cout << "
    最小生成树(克鲁斯卡尔):
    ";
            cout << endl;
            MiniSpanTree_Kruskal(G);
        }
        cout << endl;
    
        int num_start, num_destination;
        VerTexType start, destination;
        cout << "请依次输入起始点、终点名称:";
        cin >> start >> destination;
        num_start = LocateVex(G, start);
        num_destination = LocateVex(G, destination);
        ShortestPath_DIJ(G, num_start);
        cout << endl << "最短路径为:";
        DisplayPath(G, num_start, num_destination);
        cout << G.vexs[num_destination] << endl;
    
        return 0;
    }

    运行结果:

  • 相关阅读:
    双屏显示器
    Cheat Engine Tutorial v3翻译Cheat Engine 6.1 tutorial(3)
    [转]VC6创建UNICODE版Windows程序
    fread
    [转]回调函数在MFC中的使用
    [转]C++ 虚函数表解析
    [转]C/C++返回内部静态成员的陷阱
    [转]EVC 中 include 的错误
    【rgw压缩】
    【ceph | 运维】rgw重置
  • 原文地址:https://www.cnblogs.com/cjwen/p/11177564.html
Copyright © 2020-2023  润新知