使用QT设计城市交通咨询模拟系统
源码下载地址:https://github.com/Kagarise/QT-code
跨平台可执行文件下载地址:https://github.com/Kagarise/Application
概要
任务:设计一个城市交通咨询模拟系统,利用该系统实现至少两种最优决策:最短路程到达、最省时到达等线路规划。内容:用户驾车出行由于出行目的的不同对道路路线选择的要求也有不同。例如,有的希望在途中的路程尽可能短,有的则可能希望路程中时间最短。
为了能满足广大旅客的需求,编制一个城市交通咨询模拟系统,选取城市部分位置、道路抽象为程序所需要图的顶点和边,并以城市道路长度(路程),道路的某时段的速度等信息作为图结点中的弧信息,为旅客提供这两种最优决策的交通咨询。
说明:
输入形式:构建图时,输入顶点、弧涉及的信息,包括:起始地、目的地、长度、该弧此时间段的平均速度等信息;用户或者客户要输入出发地和目的地,并选择何种最优决策的路线规划。
输出形式:根据用户需求输出对应信息输出最短路程所需要的路线信息和最短路程;输出最短时间所需要的路线信息和最短时间。
界面形式:实现一个简单的交互式界面,包括系统菜单、清晰的输入提示等。根据输入的交通图数据,以图形化形式把交通图显示在屏幕上。以图形化形式把最优路线显示在屏幕上。
图的初步存储
- mapinfo.h
1 |
|
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
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(); // 将最短路加入到结果集中
}; - 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
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
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(); // 将最短路加入到结果集中
}; - 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
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
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;
}; - 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
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
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);
}; - dialog.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.