The minimum spanning tree of the graph of the data structure and the single source shortest path algorithm (C++ program description)

//This program uses C++ for various traversal algorithms of graphs, based on the idea of ​​greedy algorithms;

//The reference book is <<Interesting Algorithm>> by People's Posts and Telecommunications Press;

//Portability program can run under Linux/Mac os/Windows;

//If you have any shortcomings, please raise them, and the blogger will do their best to modify;

//If it is useful to you, please like to collect or share with others;

// Plagiarism and reprinting without permission is strictly prohibited;

//The source code is here, I hope to inspire you;

//----------------------------------------------------------------------------------------------------;

//prim seeks the minimum spanning tree.cpp

/*
    数据如下:
    城市数量: 7
    城市之间边的数量: 12
    结点数u, v和权值w是:
        1 2 23
        1 6 28
        1 7 36
        2 3 20
        2 7 1
        3 4 15
        3 7 4
        4 5 3
        4 7 9
        5 6 17
        5 7 16
        6 7 25
    输入其中一个城市结点: 1
    最小花费应该分别是: 0 23 4 9 3 17 1
    最小花费总和为: 57
*/

#include <iostream>
#include <climits>
using namespace std;

const int N = 100;
static bool flag[N];   //标记城市是否已经被访问过;
static int map[N][N];  //记录城市间的关系(邻接矩阵);
static int closest[N]; //记录城市之间的最近点;
static int lowcost[N]; //记录城市之间的最小开销;

void prim(int n, int u, int (*map)[N]);

int main(void)
{
    
    
    int i, j, n, m, u, v, w, st, sumcost;

    cout << "请您输入城市的个数: ";
    cin >> n;
    cout << "请您输入城市之间的边数: ";
    cin >> m;
    for (i = 1; i <= n; i++)
    {
    
    
        for (j = 1; j <= n; j++)
        {
    
    
            map[i][j] = INT_MAX; //顶点之间都初始化为无关联;
        }
    }
    cout << "请您输入城市之间的路线以及距离:\n";
    for (i = 1; i <= m; i++)
    {
    
    
        cin >> u >> v >> w;
        map[u][v] = map[v][u] = w; //无向图赋权值;
    }
    cout << "输入其中一个城市顶点: ";
    cin >> st;
    prim(n, st, map);
    cout << "最小花费分别是:" << endl;
    for (i = 1, sumcost = 0; i <= n; i++)
    {
    
    
        cout << lowcost[i] << ' ';
        sumcost += lowcost[i]; //累增最小花费数额;
    }
    cout << "\n最小花费总和: " << sumcost << endl;

    return 0;
}

void prim(int n, int u, int (*map)[N])
{
    
    
    int i, j, t, temp;

    flag[u] = true; //令u顶点加入至最小生成树中;
    for (i = 1; i <= n; i++)
    {
    
    
        if (i != u)
        {
    
    
            lowcost[i] = map[u][i]; //初始化为u顶点到除u顶点外每个顶点的权值;
            closest[i] = u;         //初始化所有顶点的邻近关系都与u有关联;
            flag[i] = false;        //初始化除u之外的顶点不属于最小生成树中的集合;
        }
        else
        {
    
    
            lowcost[i] = 0; //自身的权值为0;
            closest[i] = u; //自身的最近城市为自己;
        }
    }
    for (i = 1; i <= n; i++)
    {
    
    
        temp = INT_MAX;
        t = u;
        for (j = 1; j <= n; j++)
        {
    
    
            if (!flag[j] && lowcost[j] < temp) //在V - U集合中寻找距离最小生成树集合最近的顶点t;
            {
    
    
                t = j;
                temp = lowcost[j];
            }
        }
        if (t == u)
        {
    
    
            break;
        }
        flag[t] = true;
        for (j = 1; j <= n; j++)
        {
    
    
            if (!flag[j] && map[t][j] < lowcost[j]) //t到j的权值小于当前的邻近顶点的最小权值;
            {
    
    
                lowcost[j] = map[t][j]; //更新j的最邻近权值为t到j的边权值;
                closest[j] = t;         //更新j的最邻近点为t;
            }
        }
    }
    return;
}

//----------------------------------------------------------------------------------------------------;

//kruskal seeking minimum spanning tree.cpp

/*
    数据如下:
    城市数量: 7
    城市之间边的数量: 12
    结点数u, v和权值w是:
        1 2 23
        1 6 28
        1 7 36
        2 3 20
        2 7 1
        3 4 15
        3 7 4
        4 5 3
        4 7 9
        5 6 17
        5 7 16
        6 7 25
    城市结点从1开始进行计费;
    最小花费总和为: 57
*/

#include <iostream>
#include <algorithm>
using namespace std;

const int N = 100;
static int n, m;       //城市的个数以及城市的边数;
static int nodeset[N]; //结点的集合号;
struct Edge
{
    
    
    int u; //结点的行边;
    int v; //结点的列边;
    int w; //结点的权值;
} e[N * N];

bool comp(Edge x, Edge y); //比较边之间的权值:
void init(int n);          //初始化每个城市的集合号;
int merge(int a, int b);   //对每个城市的集合号进行处理;
int kruskal(int n);        //kruskal算法构造最小生成树;

int main(void)
{
    
    
    cout << "请您输入城市的个数: ";
    cin >> n;
    cout << "请您输入城市之间的边数: ";
    cin >> m;
    init(n);
    cout << "请您输入城市之间的路线以及距离:\n";
    for (int i = 0; i < m; i++)
    {
    
    
        cin >> e[i].u >> e[i].v >> e[i].w;
    }
    sort(e, e + m, comp); //依据边的权值来进行升序排序;
    cout << "最小的花费是:" << kruskal(n) << endl;

    return 0;
}

bool comp(Edge x, Edge y)
{
    
    
    return x.w < y.w;
}

void init(int n)
{
    
    
    for (int i = 1; i <= n; i++)
    {
    
    
        nodeset[i] = i; //初始化每一个城市的集合号;
    }
    return;
}

int merge(int a, int b)
{
    
    
    int p = nodeset[a];
    int q = nodeset[b];

    if (p == q)
    {
    
    
        return 0;
    }
    for (int i = 1; i <= n; i++) //检查所有结点, 把集合号是q的改为p;
    {
    
    
        if (nodeset[i] == q)
        {
    
    
            nodeset[i] = p; //a的集合号赋值给b集合号;
        }
    }
    return 1;
}

int kruskal(int n)
{
    
    
    for (int i = 0, ans = 0; i < m; i++)
    {
    
    
        if (merge(e[i].u, e[i].v)) //2个结点不属于同一个集合;
        {
    
    
            ans += e[i].w; //累增一条边的权值;
            if (--n == 1)
            {
    
    
                return ans;
            }
        }
    }
    return 0;
}

//----------------------------------------------------------------------------------------------------;

//dijkstra finds the shortest path of a single source.cpp

/*
    数据如下:
    城市个数: 5
    城市之间路线个数: 11
    城市之间路线以及距离:
        1 5 12
        5 1 8
        1 2 16
        2 1 29
        5 2 32
        2 4 13
        4 2 27
        1 3 15
        3 1 21
        3 4 7
        4 3 19
    您所在的位置可以输入是: 5
    预计输出是:
    5 -> 1 == 8
    5 -> 2 == 24
    5 -> 3 == 23
    5 -> 4 == 30
    5 -> 5 == 0
*/

#include <iostream>
#include <climits>
#include <stack>
using namespace std;

const int N = 100;
static bool flag[N];  //标记城市是否已经被访问过;
static int map[N][N]; //记录城市间的关系(邻接矩阵);
static int cities[N]; //记录城市的最短路径路线;
static int dist[N];   //记录城市间的最短距离;

void print_path(int u, int n);      //打印源点u到各个关联顶点的最短路径路线;
void dijkstra(int u, int n, int m); //求单源最短路径算法;

int main(void)
{
    
    
    int i, j, u, v, w, st, n, m;
    //u和v是邻接矩阵的位置, w是权值;
    //st是用户当前所在位置;
    //n是城市的个数, m是城市间路线的条数;

    cout << "请您输入城市的个数: ";
    cin >> n;
    cout << "请您输入城市之间的路线的个数: ";
    cin >> m;
    for (i = 1; i <= n; i++)
    {
    
    
        for (j = 1; j <= n; j++)
        {
    
    
            map[i][j] = INT_MAX; //顶点之间都初始化为无关联;
        }
    }
    cout << "请您输入城市之间的路线以及距离:\n";
    while (m--)
    {
    
    
        cin >> u >> v >> w;
        map[u][v] = min(map[u][v], w); //防止用户输入了2个顶点相同距离造成距离改变, 所以取的是最短的距离;
    }
    cout << "请输入您所在的当前位置: ";
    cin >> st;
    dijkstra(st, n, m);
    cout << "您当前所在的位置是: " << st << endl;
    print_path(st, n);

    return 0;
}

void print_path(int u, int n)
{
    
    
    int x;
    stack<int> s;

    for (int i = 1; i <= n; i++)
    {
    
    
    	if (i == u)
    	{
    
    
    		continue;
    	}
        x = cities[i];
        while (x != -1)
        {
    
    
            s.push(x);
            x = cities[x];
        }
        cout << "此位置到" << i << "顶点的最短路径是: ";
        while (!s.empty())
        {
    
    
            cout << s.top() << " -> ";
            s.pop();
        }
        cout << i << "\n最短距离是: " << dist[i] << endl;
    }
    return;
}

void dijkstra(int u, int n, int m)
{
    
    
    int i, j, t, temp;

    for (i = 1; i <= n; i++)
    {
    
    
        dist[i] = map[u][i]; //初始化源点u到其它各个顶点的最短路径长度;
        flag[i] = false;
        if (dist[i] == INT_MAX)
        {
    
    
            cities[i] = -1; //说明源点u到顶点i无边相连;
        }
        else
        {
    
    
            cities[i] = u; //说明源点u到顶点i有边相连;
        }
    }
    flag[u] = true; //初始化集合中只有一个元素u被访问过;
    dist[u] = 0;    //初始化源点u到自己的最短路径为0;
    for (i = 1; i <= n; i++)
    {
    
    
        temp = INT_MAX;
        t = u;
        for (j = 1; j <= n; j++) //在集合V - S中寻找距离源点u最近的顶点t;
        {
    
    
            if (!flag[j] && dist[j] < temp)
            {
    
    
                t = j;          //记录距离源点u最近的顶点;
                temp = dist[j]; //记录j顶点当前的距离;
            }
        }
        if (t == u) //若找不到t则退出此函数, 无需再求最短路径;
        {
    
    
            return;
        }
        flag[t] = true;          //否则则标记t为被访问的结点;
        for (j = 1; j <= n; j++) //更新集合V - S中与t邻接的顶点到源点u的距离;
        {
    
    
            if (!flag[j] && map[t][j] != INT_MAX)
            {
    
    
                if (dist[j] > (dist[t] + map[t][j])) //经过t到达j的路径更短;
                {
    
    
                    dist[j] = dist[t] + map[t][j];
                    cities[j] = t; //记录j顶点的前驱为t;
                }
            }
        }
    }
    return;
}

//----------------------------------------------------------------------------------------------------;

//------------------------------------------------ -November 14, 2020------------------------------------------- ------------;

Guess you like

Origin blog.csdn.net/m0_46181359/article/details/109695811