源码下载地址:https://github.com/Kagarise/QT-code
跨平台可执行文件下载地址:https://github.com/Kagarise/Application

概要

任务:设计一个城市交通咨询模拟系统,利用该系统实现至少两种最优决策:最短路程到达、最省时到达等线路规划。
内容:用户驾车出行由于出行目的的不同对道路路线选择的要求也有不同。例如,有的希望在途中的路程尽可能短,有的则可能希望路程中时间最短。
为了能满足广大旅客的需求,编制一个城市交通咨询模拟系统,选取城市部分位置、道路抽象为程序所需要图的顶点和边,并以城市道路长度(路程),道路的某时段的速度等信息作为图结点中的弧信息,为旅客提供这两种最优决策的交通咨询。
说明
输入形式:构建图时,输入顶点、弧涉及的信息,包括:起始地、目的地、长度、该弧此时间段的平均速度等信息;用户或者客户要输入出发地和目的地,并选择何种最优决策的路线规划。
输出形式:根据用户需求输出对应信息输出最短路程所需要的路线信息和最短路程;输出最短时间所需要的路线信息和最短时间。
界面形式:实现一个简单的交互式界面,包括系统菜单、清晰的输入提示等。根据输入的交通图数据,以图形化形式把交通图显示在屏幕上。以图形化形式把最优路线显示在屏幕上。

图的初步存储

  • mapinfo.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#ifndef MAPINFO_H
#define MAPINFO_H

#include <set>
#include <vector>
#include <utility>
using namespace std;

const int inf = 0x3f3f3f3f;

class Cost
{
public:
double dis, tim; // 距离、时间
Cost(){
this->dis = 0;
this->tim = 0;
}
Cost(double dis, double tim) {
this->dis = dis;
this->tim = tim;
}
};

class SideInfo{
public:
int u, v; // 起点,终点
double dis, tim; // 距离,时间
SideInfo(int u, int v, double dis, double speed){
this->u = u;
this->v = v;
this->dis = dis;
this->tim = dis/speed;
}
};

class MapInfo
{
public:
int vexnum, arcnum; // 顶点数、边数
vector<SideInfo> side_info_vec; // 边信息集
set<pair<int, int> > side_set; // 最短路径结果集
int st, en; // 起点、终点
MapInfo() {
vexnum = arcnum = 0;
st = en = 0;
side_info_vec.clear();
side_set.clear();
}
};

#endif // MAPINFO_H

Floyd算法

  • floyd.h
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    #ifndef FLOYD_H
    #define FLOYD_H

    #include "mapinfo.h"

    #include <iostream>

    #define F 110

    class Floyd{
    public:
    int vexnum, arcnum;
    int st, en;
    Cost G[F][F]; // 图
    int Path[F][F]; // 记录路径信息

    set<pair<int, int> > side_set; // 最短路径结果集

    void init(MapInfo map); // 初始化图
    void solveByDistance(); // 最短路径
    void solveByTime(); // 最短时间
    set<pair<int, int> > findWay(); // 将最短路加入到结果集中
    };

    #endif // FLOYD_H
  • floyd.cpp
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    #include"floyd.h"

    void Floyd::init(MapInfo map){
    vexnum = map.vexnum;
    arcnum = map.arcnum;
    st = map.st;
    en = map.en;
    // init G ans Path
    for (int i = 0; i <= vexnum; i++)
    for (int j = 0; j <= vexnum; j++)
    if (i == j)
    G[i][j] = Cost(0, 0), Path[i][j] = -1;
    else
    G[i][j] = Cost(inf, inf), Path[i][j] = j;
    // Read G
    int len = map.side_info_vec.size();
    for(int i = 0; i < len; i++){
    SideInfo s = map.side_info_vec[i];
    G[s.u][s.v] = Cost(s.dis, s.tim);
    }
    }

    void Floyd::solveByDistance(){
    for (int k = 1; k <= vexnum; k++)
    for (int i = 1; i <= vexnum; i++)
    for (int j = 1; j <= vexnum; j++)
    if (G[i][k].dis + G[k][j].dis < G[i][j].dis){
    G[i][j].dis = G[i][k].dis + G[k][j].dis;
    G[i][j].tim = G[i][k].tim + G[k][j].tim;
    Path[i][j] = Path[i][k];
    }
    }

    void Floyd::solveByTime(){
    for (int k = 1; k <= vexnum; k++)
    for (int i = 1; i <= vexnum; i++)
    for (int j = 1; j <= vexnum; j++)
    if (G[i][k].tim + G[k][j].tim < G[i][j].tim){
    G[i][j].dis = G[i][k].dis + G[k][j].dis;
    G[i][j].tim = G[i][k].tim + G[k][j].tim;
    Path[i][j] = Path[i][k];
    }
    }

    set<pair<int, int> > Floyd::findWay(){
    if (G[st][en].dis == inf) {
    cout << "No Way!!!" << endl;
    }else{
    cout << "Floyd SSP: dis = " << G[st][en].dis << " time = " << G[st][en].tim << endl;
    int pos = Path[st][en];
    cout << st;
    side_set.insert(make_pair(st, pos));
    while (pos != en) {
    int cas = pos;
    cout << "->" << pos;
    pos = Path[pos][en];
    side_set.insert(make_pair(cas, pos));
    }
    cout << "->" << en << endl;
    }
    return side_set;
    }

    Dijkstra算法

  • dijkstra.h
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    #ifndef DIJKSTRA_H
    #define DIJKSTRA_H

    #include "mapinfo.h"

    #include <queue>
    #include <iostream>

    #define N 10010

    typedef pair<int, Cost> pic;

    class Dijkstra{
    public:
    int vexnum, arcnum;
    int st, en;
    Cost cost[N]; // 记录最小消耗
    vector<pair<int, Cost> > G[N]; // 图
    vector<int> Path[N]; // 记录路径信息

    set<pair<int, int> > side_set; // 最短路径结果集

    void init(MapInfo map); // 初始化图
    void solveByDistance(); // 最短路径
    void solveByTime(); // 最短时间
    set<pair<int, int> > findWay(); // 将最短路加入到结果集中
    };

    #endif // DIJKSTRA_H
  • dijkstra.cpp
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    #include "dijkstra.h"

    void Dijkstra::init(MapInfo map){
    vexnum = map.vexnum;
    arcnum = map.arcnum;
    st = map.st;
    en = map.en;
    // init cost
    for (int i = 0; i <= vexnum; i++){
    cost[i] = Cost(inf, inf);
    }
    // Read G
    int len = map.side_info_vec.size();
    for(int i = 0; i < len; i++){
    SideInfo s = map.side_info_vec[i];
    G[s.u].push_back(make_pair(s.v, Cost(s.dis, s.tim)));
    }
    }

    void Dijkstra::solveByDistance(){
    struct cmp{
    bool operator() (pic A, pic B){
    if(A.second.dis == B.second.dis)
    return A.second.tim > B.second.tim;
    return A.second.dis > B.second.dis;
    }
    };
    priority_queue<pic, vector<pic>, cmp > Q;
    cost[st] = Cost(0, 0);
    Q.push(make_pair(st, cost[st]));
    while(!Q.empty()){
    pic tmp = Q.top();
    Q.pop();
    int v = tmp.first;
    if(cost[v].dis < tmp.second.dis)
    continue;
    int len = G[v].size();
    for(int i = 0; i < len; i++){
    pic e = G[v][i];
    if(cost[e.first].dis > cost[v].dis + e.second.dis){
    cost[e.first].dis = cost[v].dis + e.second.dis;
    cost[e.first].tim = cost[v].tim + e.second.tim;
    Q.push(make_pair(e.first, cost[e.first]));
    Path[e.first] = Path[v];
    Path[e.first].push_back(v);
    }
    }
    }
    }

    void Dijkstra::solveByTime(){
    struct cmp{
    bool operator() (pic A, pic B){
    if(A.second.tim == B.second.tim)
    return A.second.dis > B.second.dis;
    return A.second.tim > B.second.tim;
    }
    };
    priority_queue<pic, vector<pic>, cmp > Q;
    cost[st] = Cost(0, 0);
    Q.push(make_pair(st, cost[st]));
    while(!Q.empty()){
    pic tmp = Q.top();
    Q.pop();
    int v = tmp.first;
    if(cost[v].tim < tmp.second.tim)
    continue;
    int len = G[v].size();
    for(int i = 0; i < len; i++){
    pic e = G[v][i];
    if(cost[e.first].tim > cost[v].tim + e.second.tim){
    cost[e.first].tim = cost[v].tim + e.second.tim;
    cost[e.first].dis = cost[v].dis + e.second.dis;
    Q.push(make_pair(e.first, cost[e.first]));
    Path[e.first] = Path[v];
    Path[e.first].push_back(v);
    }
    }
    }
    }

    set<pair<int, int> > Dijkstra::findWay(){
    if (cost[en].dis == inf) {
    cout << "No Way!!!" << endl;
    }else{
    cout << "Dijkstra SSP: dis = " << cost[en].dis << " time = " << cost[en].tim << endl;
    int pos = -1;
    int len = Path[en].size();
    for(int i = 0; i < len; i++){
    cout << Path[en][i] << "->";
    side_set.insert(make_pair(pos, Path[en][i]));
    pos = Path[en][i];
    }
    side_set.insert(make_pair(pos, en));
    cout << en << endl;
    }
    return side_set;
    }

    整体架构与界面设计

  • ssp.h
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    #ifndef SSP_H
    #define SSP_H

    #include "mapinfo.h"
    #include "dialog.h"

    #include <QWidget>
    #include <QLabel>

    namespace Ui {
    class ssp;
    }

    class ssp : public QWidget
    {
    Q_OBJECT

    public:
    explicit ssp(QWidget *parent = 0);
    ~ssp();
    MapInfo map;
    QLabel *myLabel = new QLabel(this);
    vector<QLabel*> V;
    bool paintPause = true;
    void initMap();
    void deleteV();

    private slots:
    void on_pushButtonNew_clicked();
    void on_pushButtonOld_clicked();

    void on_pushButtonCalculate_clicked();

    void receiveData(QString data);


    private:
    Ui::ssp *ui;
    void paintEvent(QPaintEvent *event);
    Dialog *dialog;
    };

    #endif // SSP_H
  • ssp.cpp
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    #include "ssp.h"
    #include "ui_ssp.h"
    #include "floyd.h"
    #include "dijkstra.h"

    #include <QFile>
    #include <QPoint>
    #include <QLabel>
    #include <QString>
    #include <QPainter>
    #include <QFileDialog>
    #include <QTextStream>

    #include <cmath>

    QString dialogData;

    ssp::ssp(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::ssp)
    {
    ui->setupUi(this);

    // widget style
    QString widgetQSS = "QWidget{border: 2px solid #CCC; border-radius: 5px;}";

    ui->widgetLeft->setStyleSheet(widgetQSS);
    ui->widgetRight->setStyleSheet(widgetQSS);

    // Load new style
    // QString bQSS = "QPushButton{border: 2px solid #0FF; border-radius: 5px;}";
    // QPushButton *bLoad = ui->pushButtonOld;
    // bLoad->setStyleSheet(bQSS);

    // Set radioButton default value
    ui->radioButtonFloyd->setChecked(true);
    ui->radioButtonDistance->setChecked(true);
    }

    ssp::~ssp()
    {
    delete ui;
    }

    void ssp::on_pushButtonNew_clicked()
    {
    dialog = new Dialog(this);
    dialog->setModal(true);
    connect(dialog, SIGNAL(sendData(QString)), this, SLOT(receiveData(QString)));
    dialog->show();
    }

    void ssp::on_pushButtonOld_clicked()
    {
    QString filePath = QFileDialog::getOpenFileName(this, "Load Map", "../", "TXT(*.txt)");
    if(!filePath.isEmpty()){
    QFile file(filePath);
    if(file.open(QIODevice::ReadOnly)){
    // Read Start
    QTextStream ss(&file);
    initMap();
    ss >> map.vexnum >> map.arcnum;
    for(int i = 0; i < map.arcnum; i++){
    int u, v;
    double dis, speed;
    ss >> u >> v >> dis >> speed;
    map.side_info_vec.push_back(SideInfo(u, v, dis, speed));
    }
    // Read End
    deleteV();
    update();
    }
    file.close();
    }
    }

    void ssp::on_pushButtonCalculate_clicked()
    {
    bool algo = ui->radioButtonFloyd->isChecked();
    bool meth = ui->radioButtonDistance->isChecked();
    map.st = ui->lineEditStart->text().toInt();
    map.en = ui->lineEditEnd->text().toInt();
    if(algo){ // Solve By Floyd
    Floyd floyd;
    floyd.init(map);
    if(meth) floyd.solveByDistance();
    else floyd.solveByTime();
    map.side_set = floyd.findWay();
    }
    else{ // Solve By Dijkstra
    Dijkstra dijkstra;
    dijkstra.init(map);
    if(meth) dijkstra.solveByDistance();
    else dijkstra.solveByTime();
    map.side_set = dijkstra.findWay();
    }
    deleteV();
    update();
    }

    void ssp::paintEvent(QPaintEvent *event){
    // if(paintPause)
    // return;
    // paintPause = true;
    // makesure Paint Area
    int width = this->width();
    int height = this->height();
    int cX = width - width * 0.3;
    int cY = height / 2 * 1.05;
    int cR = cY * 0.7;
    int labelSize = 18;
    int len = V.size();
    QPoint QP[map.vexnum+10];
    double pi = acos(-1.0);
    // Find Point
    for(int i = 1; i <= map.vexnum; i++){
    QP[i].setX(cX + cR * cos(2 * pi * i / map.vexnum)), QP[i].setY(cY + cR * sin(2 * pi * i / map.vexnum));
    if(i > len){
    QLabel *label = new QLabel(this);
    label->setText(QString("%1").arg(i));
    label->setGeometry(rect().x() + QP[i].x(), rect().y() + QP[i].y(), labelSize, labelSize);
    label->show();
    len++;
    V.push_back(label);
    }
    else{
    myLabel = V[i-1];
    myLabel->setText(QString("%1").arg(i));
    myLabel->setGeometry(rect().x() + QP[i].x(), rect().y() + QP[i].y(), labelSize, labelSize);
    myLabel->show();
    V[i-1] = myLabel;
    }
    }
    // Draw Line
    QPainter p;
    p.begin(this);
    for(int i = 0; i < map.arcnum; i++){
    int u = map.side_info_vec[i].u, v = map.side_info_vec[i].v;
    // Result way
    if(map.side_set.count(make_pair(u,v)) || map.side_set.count(make_pair(v,u)))
    p.setPen(QPen(QColor(0,255,255), 3));
    else
    p.setPen(QPen(QColor(192,192,192), 3));
    p.drawLine(QP[u], QP[v]);
    }
    p.end();
    }

    void ssp::receiveData(QString data){
    QTextStream ss(&data);
    initMap();
    ss >> map.vexnum >> map.arcnum;
    for(int i = 0; i < map.arcnum; i++){
    int u, v;
    double dis, speed;
    ss >> u >> v >> dis >> speed;
    map.side_info_vec.push_back(SideInfo(u, v, dis, speed));
    }
    deleteV();
    update();
    }

    void ssp::initMap(){
    map.vexnum = map.arcnum = 0;
    map.st = map.en = 0;
    map.side_info_vec.clear();
    map.side_set.clear();
    paintPause = false;
    }

    void ssp::deleteV(){
    int len = V.size();
    for(int i = 0; i < len; i++){
    delete(V[i]);
    }
    V.clear();
    }

    输入框

  • dialog.h
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    #ifndef DIALOG_H
    #define DIALOG_H

    #include <QDialog>

    namespace Ui {
    class Dialog;
    }

    class Dialog : public QDialog
    {
    Q_OBJECT

    public:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();

    private slots:
    void on_pushButtonSubmit_clicked();

    private:
    Ui::Dialog *ui;
    signals:
    void sendData(QString);
    };

    #endif // DIALOG_H
  • dialog.cpp
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    #include "dialog.h"
    #include "ui_dialog.h"

    Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
    {
    ui->setupUi(this);
    }

    Dialog::~Dialog()
    {
    delete ui;
    }

    void Dialog::on_pushButtonSubmit_clicked()
    {
    emit sendData(ui->textEditMap->toPlainText());
    this->close();
    }

    ui界面设计

  • 细节不表
  • ssp.ui
  • dialog.ui

样例展示

  • sample1

    6 7
    1 2 50 1
    2 3 50 1
    3 4 100 1
    4 5 100 10
    5 6 100 10
    1 3 200 10
    4 6 100 1