C++管道铺设方案求解Dijkstra算法

直接上报告和代码~~~~

【问题描述】

设某城市有n个居民区,连接两居民区的道路有m条,长度不一。现需沿道路铺设煤气管道,使得全部居民区连通,且铺设所需管道总长最小。

【基本要求】

  采用耗费邻接矩阵为储存结构表达居民点及道路构成的网,求解最小生成树

【设计思路】

   我使用了Dijkstra算法。

我的设计思路大致分三步:

  1. 第一步生成邻接矩阵:
  • 首先根据点数point创建一个point+1Xpoint+1大小的int类型的矩阵DisMat,比如DisMat[i][j]和DisMat[j][i]就代表点i和j之间的距离,前提是数组中这两个值不为0,如果为0就代表两个点i和j之间没有通路。
  1. 第二步生成路径表:
  • 这个路径表Array中的每个结点仍为Node*类型的,比如定义一个Node*类型的指针p,p->data为int类型,代表它是哪个点(其实这个路径表是顺序存储的,Array[i]就代表第i个点,加上一个data是方便回溯时用)那么p->distance代表当前状态下这个点到点1的距离,p->check代表它是否被遍历过,为bool类型的,p->ahead代表它之前的结点。
  1. 第三步进行遍历:
  • 首先在路径表Array中找distance最小的结点,当然是点1本身了(默认点1为源点,其它点的距离都是9999),然后在DisMat中找和1相邻的点,并存到路径表中,它们的ahead都是结点1,然后再找distance最小的结点,比如点3,这个点是和1最近的点,把它的check改为false,意思就是点1到点3的最短路径找到了,然后在DisMat中找和点3相邻的点,如果某个点4也和1相邻,但是经过点3到点4的距离比从点1直接到点4的距离近,那么就更新结点4的distance和ahead,然后重复在路径表中找distance最小的过程,直到路径表中的每个结点的check都为false。
  • 关于输出的过程,因为每个结点都记录了它上一个结点的地址,那么回溯输出就行。加一个小小的数组把输出方式反向比如3←4←1变成1→4→3就行了。

【测试数据】

【输出结果】

【总结体会】

其实这个程序和必做题一样有很多问题,比如有多个全局变量,限制了函数的局限性。其次就是点的输入有很多要求,必须从1开始依次输入,比如1,2,3,4,…不能隔点输入,比如1,3,7,…还有的问题就是不能判断是否是两片或者多片区域,比如1,2,3,4之间有通路,5,6,7,8之间有通路,但是两片区域之间没有通路等等,总之需要很多优化,或者还有很多地方没有考虑到~~~~比如可以将结点的data变成char类型,记录点的名称,比如北京西安南京~~~~

源代码如下:

#include<iostream>
using namespace std;
//邻接矩阵定义
int** DisMat;
//结点定义
struct Node {
    int data;
    int distance;
    bool check;
    Node* ahead;
};
//路径表定义
Node** Array;
//邻接矩阵的创建
bool Creat(int point, int line) {
    if (point == 0 && line == 0) { cout << "该图为空图。" << endl; return false; }
    if (point == 0 && line != 0 || point != 0 && line == 0) { cout << "该图是错的。" << endl; return false; }
    DisMat = new int* [point+1];
    for (int i = 0; i <= point; i++){
        DisMat[i] = new int[point+1];
    }
    for (int i = 0; i <= point; i++) {
        for (int j = 0; j <= point; j++) {
            DisMat[i][j] = 0;
        }
    }
    int head; int tail; int distance; int i = 1;
    cout << "请从点1开始输入。" << endl;
    while (line != 0) {
        cout << "请输入第" << i << "条边的头、尾以及长度" << endl;
        cin >> head >> tail >> distance;
        DisMat[head][tail] = distance;
        DisMat[tail][head] = distance;
        i++;
        line--;
    }
    return true;
}
//遍历更新
void Traverse(int point, int line) {
    int min = 999;
    Node* best = new Node;
    for (int i = 1; i <= point; i++) {
        if (Array[i]->check == true && (Array[i]->distance) < min) {
            min = Array[i]->distance;
            best = Array[i];
        }
    }
    int bests = best->data;
    Array[bests]->check = false;
    for (int i = 1; i <= point; i++) {
        if (DisMat[bests][i] != 0 && Array[i]->check == true && ((Array[i]->distance) > (DisMat[bests][i] + Array[bests]->distance))) {
            Array[i]->distance = DisMat[bests][i] + Array[bests]->distance;
            Array[i]->ahead = Array[bests];
        }
    }
    for (int i = 1; i <= point; i++) {
        if (Array[i]->check == true)Traverse(point, line);
    }
}
//遍历准备
void bTraverse(int point, int line) {
    Array = new Node * [point + 1];
    for (int i = 1; i <= point; i++) {
        Node* example = new Node;
        example->distance = 9999;
        example->ahead = NULL;
        example->data = i;
        example->check = true;
        Array[i] = example;
    }
    Array[1]->distance = 0;
    Traverse(point, line);
}
//程序准备及运行
int main() {
    cout << "请输入点数和边数" << endl;
    int point, line;
    cin >> point >> line;
    Creat(point, line);
    bTraverse(point, line);
    for (int i = 2; i <= point; i++) {
        if (Array[i]->distance!=9999) {
            int end[100] = { 0 }; int tran = 99;
            Node* x = Array[i];
            cout << "点1到点" << i << "的最短路径为:";
            while (x->ahead != NULL) {
                end[tran] = x->data;
                tran--;
                x = x->ahead;
            }
            end[tran] = x->data;
            for (int i = 0; i <= 98; i++) {
                if (end[i] != 0)cout << end[i] << "→";
            }
            cout << end[99] << endl;
            cout << "点1到点" << i << "的最短距离为:";
            cout << Array[i]->distance << endl;
        }
        else {
            cout << "点1到点" << i << "没有通路。" << endl;
        }
    }
}

  • 4
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
以下是C++使用邻接矩阵实现Dijkstra算法的示例代码: ```c++ #include <iostream> #include <limits.h> #define V 9 // 找到距离最小的未访问节点 int min_distance(int dist[], bool visited[]) { int min_dist = INT_MAX, min_index = -1; for (int v = 0; v < V; v++) { if (!visited[v] && dist[v] <= min_dist) { min_dist = dist[v]; min_index = v; } } return min_index; } // 打印最短路径 void print_path(int parent[], int j) { if (parent[j] == -1) { std::cout << j << " "; return; } print_path(parent, parent[j]); std::cout << j << " "; } // Dijkstra算法 void dijkstra(int graph[V][V], int src) { int dist[V], parent[V]; bool visited[V]; for (int i = 0; i < V; i++) { dist[i] = INT_MAX; visited[i] = false; parent[i] = -1; } dist[src] = 0; for (int count = 0; count < V - 1; count++) { int u = min_distance(dist, visited); visited[u] = true; for (int v = 0; v < V; v++) { if (!visited[v] && graph[u][v] && dist[u] != INT_MAX && dist[u] + graph[u][v] < dist[v]) { dist[v] = dist[u] + graph[u][v]; parent[v] = u; } } } std::cout << "最短路径:" << std::endl; for (int i = 0; i < V; i++) { std::cout << src << " -> " << i << " 距离:" << dist[i] << " 路径:"; print_path(parent, i); std::cout << std::endl; } } int main() { int graph[V][V] = { { 0, 4, 0, 0, 0, 0, 0, 8, 0 }, { 4, 0, 8, 0, 0, 0, 0, 11, 0 }, { 0, 8, 0, 7, 0, 4, 0, 0, 2 }, { 0, 0, 7, 0, 9, 14, 0, 0, 0 }, { 0, 0, 0, 9, 0, 10, 0, 0, 0 }, { 0, 0, 4, 14, 10, 0, 2, 0, 0 }, { 0, 0, 0, 0, 0, 2, 0, 1, 6 }, { 8, 11, 0, 0, 0, 0, 1, 0, 7 }, { 0, 0, 2, 0, 0, 0, 6, 7, 0 } }; dijkstra(graph, 0); return 0; } ``` 上述代码中,我们使用邻接矩阵表示图,dist数组存储源点到各个节点的距离,parent数组存储最短路径上每个节点的前驱节点,visited数组表示该节点是否被访问过。在Dijkstra算法中,我们通过找到距离最小的未访问节点,以及对其邻接点进行松弛操作,来逐步求解源点到各个节点的最短距离。最后打印出最短路径和距离即可。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值