利用Dijkstra算法解决有权最短路径问题

  前两天同学让我帮他解决一个数学建模作业问题,题目大致描述如下:
  说某市有两个蔬菜生产基地,现在要从这两个生产基地生产蔬菜运送到各个该市的各个城镇。告诉你各个城镇之间的道路连接情况,包括道路长度。已知运输距离和运输成本成正相关,求一个生产方案使得运输成本最低。
  

输入如下:

城镇A编号   城镇B编号   道路长度
1   100 21.14
1   16  30.67
1   16  30.67
...
...
注:
1、生产基地分别在63号城镇和120号城镇。
2、需要蔬菜的城镇为: 20,106,63,31,141,10,65,79,1,120,36,27,34,42,94,11,24,63,145,22,16,123,64

简单来说,就是求出各个城镇从哪个基地生产运输起来更便宜,是一个典型的有权最短路径问题。主要思路是,对于每个城镇,计算其到两个基地的最短距离。哪个距离短,就找哪个基地生产。

C++代码

#include <iostream>
#include <string>
#include <sstream>
#include <list>
#include <vector>
#include <map>
#include <utility>
#include <cfloat>
#include <iomanip>
using namespace std;

//表示生产基地的常量,避免magic number
const int START_CITY_A = 63;
const int START_CITY_B = 120;

// 在Dijkstra算法中保存顶点的数据结构
struct Vertex
{
    vector<pair<int, double>> adjacent;//邻接编号和通往的距离
    bool known;                        //是否被处理
    double distance;                   //当前最短距离簿记
    int  path;                         //路径记录,指向距离自己最近的前一顶点
};

//读入输入数据,构建图
void creatMap(map<int,Vertex> & vertexs);
//Dijsktra核心实现
void useDijsktra(map<int,Vertex> & vertexs, int);

//Dijsktra算法所需要的子函数,查询未处理顶点和最近顶点
bool thereIsUnown(map<int,Vertex> & vertexs);
int findMinDisUnknown(map<int,Vertex> & vertexs);

//打印路径结果
void printResult(map<int,Vertex> & vertex, int city);

int main()
{
    //第一步,用邻接表构建一个图
    map<int,Vertex> vertexsA;
    creatMap(vertexsA);
    //由于要比较路径先做一个备份图
    map<int,Vertex> vertexsB = vertexsA;

    //对两张图应用Dijsktra算法
    useDijsktra(vertexsA, START_CITY_A);
    useDijsktra(vertexsB, START_CITY_B);

    //需要蔬菜的城镇编号
    int chain[] = {120,106,63,31,141,10,65,79,1,120,36,27,34,42,94,11,24,63,145,22,16,123,64};

    for(auto it = begin(chain); it != end(chain); ++it)
    {
        if(vertexsA[*it].distance >= vertexsB[*it].distance)
        {
            cout<<"连锁店地点" <<  *it << '\t' << "生产地点:\t" <<  START_CITY_B << '\t' << "总距离:\t" <<  setprecision(3) << std::fixed <<  vertexsB[*it].distance << "   \t路径\t";
            printResult(vertexsB, *it);
            cout << endl;
        }
        else
        {
            cout<<"连锁店地点" <<  *it << '\t' << "生产地点:\t" <<  START_CITY_A << '\t' << "总距离:\t" << setprecision(3) <<  std::fixed << vertexsA[*it].distance << "   \t路径\t";
            printResult(vertexsA, *it);
            cout << endl;

        }
    }

    return 0;
}

void creatMap(map<int,Vertex> & vertexs)
{
    string forInputUse;
    while(getline(cin,forInputUse))
    {
        istringstream is(forInputUse);
        int startPoint, endPoint;
        double distance;
        is >> startPoint >> endPoint >> distance;
        vertexs[startPoint].adjacent.push_back(pair<int, double>(endPoint, distance));
        vertexs[endPoint].adjacent.push_back(pair<int, double>(startPoint, distance));
        vertexs[startPoint].distance = vertexs[endPoint].distance = DBL_MAX;
        vertexs[startPoint].known = vertexs[endPoint].known = false;
        vertexs[startPoint].path = vertexs[endPoint].path = 0;
    }
}

void useDijsktra(map<int,Vertex> & vertexs, int startPoint)
{
    vertexs[startPoint].distance = 0;
    while(thereIsUnown(vertexs))
    {
        int minDisUnknown = findMinDisUnknown(vertexs);
        vertexs[minDisUnknown].known = true;
        for(auto it = vertexs[minDisUnknown].adjacent.begin(); it != vertexs[minDisUnknown].adjacent.end(); ++it)
        {
            if(vertexs[(*it).first].known == false)
            {
                double distIncre = vertexs[minDisUnknown].distance + (*it).second;
                if(distIncre < vertexs[(*it).first].distance)
                {
                    vertexs[(*it).first].distance = distIncre;
                    vertexs[(*it).first].path = minDisUnknown;
                }
            }
        }
    }
}

bool thereIsUnown(map<int,Vertex> & vertexs)
{
    for(auto it = vertexs.begin(); it != vertexs.end(); ++it)
    {
        if((*it).second.known == false)
            return true;
    }
    return false;
}

int findMinDisUnknown(map<int,Vertex> & vertexs)
{
    int minUnknown = 0;
    double currentValue = DBL_MAX;
    for(auto it = vertexs.begin(); it != vertexs.end(); ++it)
    {
        if((*it).second.known == false)
        {
            if((*it).second.distance < currentValue)
            {
                minUnknown = (*it).first;
                currentValue = (*it).second.distance;
            }
        }
    }
    return minUnknown;
}

void printResult( map<int,Vertex> & vertex, int city)
{
    cout << city << " ";
    if(vertex[city].path != 0)
        printResult(vertex, vertex[city].path);
}

运行结果

这里写图片描述

输入数据文件: https://pan.baidu.com/s/1-cm7uAAXBjKhGmFsOzS8KA 密码: kdb6

参考书籍:数据结构与算法分析——C++语言描述(第四版)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值