目錄
問題:
背景知識:圖的存儲、遍歷及其應用,圖的最短路徑等。
目的要求:
掌握圖的存儲、構建、搜索等操作和應用,能用最短路徑及其搜索等算法編制較綜合性的程序,求解最優路線問題,進行程序設計、數據結構和算法設計等方面的綜合訓練。
實驗內容:
1.任務:設計一個城市交通諮詢模擬系統,利用該系統實現至少兩種最優決策:最短路程到達、最省時到達等線路規劃。
2.內容:
用戶駕車出行由於出行目的的不同對道路路線選擇的要求也有不同。例如,有的希望在途中的路程儘可能短,有的則可能希望路程中時間最短。爲了能滿足廣大旅客的需求,編制一個城市交通諮詢模擬系統,選取城市部分位置、道路抽象爲程序所需要圖的頂點和邊,並以城市道路長度(路程),道路的某時段的速度等信息作爲圖結點中的弧信息,爲旅客提供這兩種最優決策的交通諮詢。
實驗說明:
1.輸入和輸出:
(1)輸入形式:
- 構建圖時,輸入頂點、弧涉及的信息,包括:起始地、目的地、長度、該弧此時間段的平均速度等信息;
- 用戶或者客戶要輸入出發地和目的地,並選擇何種最優決策的路線規劃。
(2)輸出形式:根據用戶需求輸出對應信息
- 輸出最短路程所需要的路線信息和最短路程;
- 輸出最短時間所需要的路線信息和最短時間。
2.實驗要求:
-
- 實現一個簡單的交互式界面,包括系統菜單、清晰的輸入提示等。
- 根據輸入的交通圖數據,以圖形化形式把交通圖顯示在屏幕上。
- 以圖形化形式把最優路線顯示在屏幕上。
代碼1(這是題目給的代碼)
解析:
這個是實驗指導書上的源碼,挺好用
功能1:
首先你需要改代碼的路徑,也就是你存放文件的位置、,一共有三個文件
count文件裏面存的地方的個數,map文件裏面存的是一個點到另一個點的距離,map_speed文件裏面存的是 一個點到另一個點的時間
看map裏面的1,處於第1行第2列,就是第一個點到第二個點的距離是1,
map_speed的1.1就是第1個點到第2個點的花費的時間是1.1
這是我用的測試點
下面正式開始測試,首先你要改一下代碼中的文件的路徑,
運行結果圖
我們可以根據之前的測試圖,可以看到它的路線
功能2:
錄入路線
把代碼中的寫入的路徑更改一下
這個輸入的是兩個點是雙向都可以通的,點1到點2 的距離是1速度是1,
思路:很簡單,就是用弗羅伊德算法,計算出權值最小的路徑,順便用記錄中間的一些中轉點,在最後的輸出路徑中輸出出來。
弗羅裏達算法思想,想具體知道弗羅裏達算法算法自己在網上搜一下吧看吧。
代碼
稍微加了一些註釋,這個給的代碼很簡單,應該不用多說吧,不會真的有人看不懂吧
#include <stdio.h>
#include <stdlib.h>
#define inf 99999999
#define max_element 50
int e[max_element][max_element]; //保存地圖的數組
int path_e[max_element][max_element], path_t[max_element][max_element];//轉折點的路徑
double t[max_element][max_element]; //保存地圖的速度
void Menu();
void Old_Map();
void New_Map();
void Floyd(int (*e)[max_element],double (*t)[max_element], int n); //計算最短路徑
void Floyd_dist(int (*e)[max_element], int n, int start, int end);
void Floyd_time(double (*e)[max_element], int n, int start, int end);
int main()
{
int Mu=5;
Menu();
while(scanf("%d", &Mu), Mu!=0)
{
switch(Mu)//菜單選項
{
case 1: Old_Map();break;
case 2: New_Map();break;
case 3: system("cls");break;
default:printf("\n請輸入正確指令!!!");break;
}
Menu();
}
printf("\n成功退出!");
return 0;
}
void Menu()
{
printf("\n ---選擇使用已保存的地圖:1---");
printf("\n\n ---選擇重新錄入地圖信息:2---\n");
printf("\n -----------清屏:3-----------\n");
printf("\n -------------退出:0-------------\n");
}
//使用原有地圖
void Old_Map()
{
int i, j;
FILE *fp;
int count = 0;
//讀入文檔count.txt
if((fp=fopen("C:\\Users\\jin\\Desktop\\count.txt","r")) == NULL)
{
printf("File open failed!\n");
exit(0);
}
fscanf(fp,"%d", &count);//讀入點數
fclose(fp);
printf("頂點個數 == %d\n", count);
if(count == 0 )
{
printf("\n信息讀入錯誤!!\n錯誤原因:沒有已保存的地圖,請選擇重新輸入地圖信息!!\n");
return ;
}
///讀入文檔map.txt
if((fp=fopen("C:\\Users\\jin\\Desktop\\map.txt","r")) == NULL)
{
printf("File open failed!\n");
exit(0);
}
for(i = 1; i <= count; i++)
for(j = 1; j <= count; j++)
{
fscanf(fp,"%d", &e[i][j]);
}//讀入距離地圖,是一個矩陣
fclose(fp);
///讀入文檔map_speed.txt
if((fp=fopen("C:\\Users\\jin\\Desktop\\map_speed.txt","r")) == NULL)
{
printf("File open failed!\n");
exit(0);
}
for(i = 1; i <= count; i++)
for(j = 1; j <= count; j++)
{
fscanf(fp,"%lf", &t[i][j]);
}//讀入時間地圖,矩陣
fclose(fp);
///將地圖信息打印*************能否採用圖形界面將位置信息打印?
Floyd(e,t, count);
}
//新錄入地圖
void New_Map()
{
//map數組初始化
int i, j;
for(i = 0; i < max_element; i++ )
for(j = 0; j < max_element; j++)
if(i == j)
{
e[i][j] = 0;
t[i][j] = 0;
}
else {
e[i][j] = inf;
t[i][j] = inf;
}
printf("\n請輸入每條路的起點、終點、路的長度、速度\n(中間以空格隔開,按下Ctrl+Z結束輸入):\n");
int s, ee, l, speed;
int count = 0;
//地圖寫入
while(scanf("%d %d %d %d", &s, &ee, &l,&speed) != EOF)
{//開始地,目標地,距離,速度
e[s][ee] = l;
e[ee][s] = l;
t[s][ee] = (l*1.0)/speed;
t[ee][s] = (l*1.0)/speed;
printf("%.2f ", t[s][ee]);
count++;
}
///將地圖存入文件map.txt
FILE *fp;
if((fp=fopen("C:\\Users\\jin\\Desktop\\map1.txt","w")) == NULL)
{
printf("the file can not open...");
exit(0);
}
for(i = 1; i <= count; i++)
for(j = 1; j <= count; j++)
{
fprintf(fp,"%d", e[i][j]);
fprintf(fp,"\n");
}
fclose(fp);
///將速度-時間存入文件中"map_speed.txt
if((fp=fopen("C:\\Users\\jin\\Desktop\\map_speed1.txt","w")) == NULL)
{
printf("the file can not open...");
exit(0);
}
for(i = 1; i <= count; i++)
for(j = 1; j <= count; j++)
{
fprintf(fp,"%lf", t[i][j]);
fprintf(fp,"\n");
}//像文件裏面寫入速度(浮點數)
fclose(fp);
///將頂點的個數存入文件
if((fp=fopen("C:\\Users\\jin\\Desktop\\count1.txt","w")) == NULL)
{
printf("the file can not open...");
exit(0);
}
fprintf(fp,"%d", count);
fclose(fp);
Floyd(e,t, count);
}
//佛洛依德算法
void Floyd(int (*e)[max_element],double (*t)[max_element],int n)
{
int start, end; //起始位置,終點
//初始化記錄路徑詳細信息數組path
int i, j;
//初始化終點***
for( i = 0; i <= n; i++)
for(j = 0; j <= n; j++)
{
path_e[i][j] = j;
path_t[i][j] = j;
}
while(1)
{
printf("\n請輸入要查詢路徑起點、終點位置:");
scanf("%d %d", &start, &end);
if(start > n || end > n)
{
printf("\n出現錯誤!!!\n錯誤原因:輸入了不存在的頂點!!\n請重新輸入!!\n");
printf("\n頂點個數爲:%d", n);
continue;
}
int Floyd_xuanze = 0;
printf("\n請輸入查詢方式:\n");
printf("1---最短路徑\n");
printf("2---最短時間\n");
scanf("%d", &Floyd_xuanze);
/**
*異常處理
*/
switch(Floyd_xuanze)
{
case 1: Floyd_dist(e, n, start, end);break;
case 2: Floyd_time(t,n, start, end);break;
default : printf("請輸入正確指令!!!\n");break;
}
int temp = 0;
printf("是否繼續查詢:yes:1 / no:0\n");
scanf("%d", &temp);
if(!temp)
break;
}
}
void Floyd_dist(int (*e)[max_element], int n, int start, int end)
{
int k, i, j;
///佛洛依德算法---距離
for(k = 1; k<=n; k++)//中轉點
for(i = 1; i <= n; i++)
for(j = 1; j <= n; j++)
if(e[i][j]>e[i][k]+e[k][j])
{
e[i][j]=e[i][k]+e[k][j];
path_e[i][j] = path_e[i][k];//記錄中轉點
}
///打印出最短路徑及相應路徑信息--距離
printf("\n查詢成功!!信息如下:\n\n");
printf("%d=>%d, length:%d, ",start, end, e[start][end]);
int v = path_e[start][end];//最開始的中轉點
printf("path:%d", start);
while(v!=end)
{
printf("->%d",v);
v = path_e[v][end];
}
printf("->%d", end);
printf("\n___________________________________________\n");
}
void Floyd_time(double (*t)[max_element], int n, int start, int end)
{
int k, i, j;
///佛洛依德算法---時間
for(k = 1; k<=n; k++)
for(i = 1; i <= n; i++)
for(j = 1; j <= n; j++)
if(t[i][j]>t[i][k]+t[k][j])
{
t[i][j]=t[i][k]+t[k][j];
path_t[i][j] = path_t[i][k];
}
///打印出最短路徑及相應路徑信息--距離
printf("\n查詢成功!!信息如下:\n\n");
printf("%d=>%d, time:%.2fh, ",start, end, t[start][end]);
int v = path_t[start][end];
printf("path:%d", start);
while(v!=end)
{
printf("->%d",v);
v = path_t[v][end];
}
printf("->%d", end);
printf("\n___________________________________________\n");
}
代碼2(自己寫的)
前言
如果你這個看的不是很懂,建議看第一個,
不行不行啦,好想誇一誇我自己,
其實也沒啥,就是實現一箇中文的地點,用map容器進行映射。
其中的難點就是搞了我好久的一個小東西,讀取文件,一個詞,一個詞的讀取,搞得我很頭疼,不過最後巧妙的解決啦
這個東西如果只用getline(ifs, read, ' '),讀取文件的時候,當讀取到第一行最後一個詞的時候,會和第二行第一個詞一起讀,於是乎,可能應該搞了有點長時間把,想了一個巧妙的辦法給解決啦,唉這就是生活啊,兵來將擋,水來土掩。
整體思路及運行情況
思路:讀取文件裏面給的路線圖,把這些點用弗羅伊德算法,算出最優解,根據所求,輸出所要。
主要的亮點就是中文的地點,用了map容器進行一些替換
運行情況:
首先把你的文件調整成ANSI編碼,
在文件的輸入格式是,開始地名,目的地名,距離(浮點型),速度(浮點型)
這是我的地圖,畫了一下
開始運行,首先你要知道你的文件的路徑
代碼
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
map<string,int> pp;
map<int,string> qq;
#define inf 99999999
double dist[50][50],timee[50][50];
int locations = 0;
void Floyd(double mn[50][50],int choose);
void Choose();
void Floyd(double mn[50][50],int choose)
{
int path_min[50][50];//記錄中間轉折點
for(int i=1; i<=locations; i++)
for(int j=1; j<=locations; j++)
if(i!=j&&mn[i][j]==0)
{
mn[i][j] = inf;//初始化地圖
//cout<<dist[i][j]<<endl;
}
for(int i=1; i<=locations; i++)
for(int j=1; j<=locations; j++)
{
path_min[i][j] = j;//初始化轉折點
}
//弗羅裏達算法
for(int k = 1; k<=locations; k++)
for(int i=1; i<=locations; i++)
for(int j=1; j<=locations; j++)
{
if(mn[i][j]>mn[i][k]+mn[k][j])
{
mn[i][j] = mn[i][k]+mn[k][j];
path_min[i][j] = path_min[i][k];
}
}
while(1)
{
printf("請輸入出發地名和目的地名\n");
printf("出發地名:");
string ss;
cin>>ss;
int st = pp[ss];
printf("目的地名:");
string sss;
cin>>sss;
int ed = pp[sss];
cout<<"++++++++++++++++++++++++"<<endl;
cout<<(choose == 1 ? "您所需的最短路程爲:":"最短時間爲:");
cout<<mn[st][ed];
cout<<(choose == 1 ? "公里" : "小時")<<endl;
cout<<"++++++++++++++++++++++++"<<endl;
cout<<"您的路線爲:"<<endl;
cout<<"------------------------"<<endl;
cout<<ss<<"->";
int v = path_min[st][ed];
while(v!=ed)
{
cout<<qq[v]<<"->";
v = path_min[v][ed];
}
cout<<sss<<endl;
cout<<"------------------------"<<endl;
cout<<"請問是選擇再次詢問,還是退出,還是返回上一級"<<endl;
cout<<"\t1再次詢問\n"<<"\t2.返回上一級\n"<<"\t3.退出\n"<<endl;
int c;
cin>>c;
if(c==1) {}
else if(c==2)
Choose();
else if(c==3)
return;
}
}
void Choose()
{
printf("請選擇查詢方式\n");
printf("1.最短路徑\t");
printf("2.最短時間\t\n");
int choose;
cin>>choose;
if(choose==1)
{
Floyd(dist,choose);//最短路程
}
else if(choose==2)
{
Floyd(timee,choose);//最少時間
}
else
{
cout<<"您輸入的指令有誤,請重新輸入"<<endl;
Choose();
}
}
int main()
{
int id=1;
cout<<"請輸入您地圖的位置"<<endl;
string Path;
cin>>Path;//輸入位置
char path[100];
for(int i=0; i<Path.length(); i++)
path[i] = Path[i];
ifstream ifs(path);
if(ifs!=NULL) cout<<"您的地圖已被打開已經被打開"<<endl;
string read;
int ans = 0;
string start,end;//出發地,目標地
double dis,sp;//距離,速度
while(getline(ifs, read, ' '))
{
if(ans%4==0)//讀取的第一個詞
{
start = read;
//cout<<"開始地"<<read<<endl;
}
if(ans%4==1)//讀取的第二個詞
{
end = read;
//cout<<"目標地"<<read<<endl;
}
if(ans%4==2)//讀取的第三個詞和第四個詞
{
char s1[10];
for(int i=0; i<read.length(); i++)
s1[i] = read[i];
dis = atof(s1);
// cout<<"距離"<<read<<endl;
getline(ifs, read, '\n');
char s2[10];
for(int i=0; i<read.length(); i++)
s2[i] = read[i];
sp = atof(s2);
// cout<<"速度"<<read<<endl;
ans++;
}
//cin>>start>>end>>dis>>sp;
if(ans%4==3)//四個讀取完開始儲存
{
if(pp[start]==0)//如果這個地點沒有被儲存,便開始儲存
{
pp[start] = id;//地點對應的序號
qq[id] = start;
id++;
}
if(pp[end]==0)
{
pp[end] = id;
qq[id] = end;
id++;
}
dist[pp[start]][pp[end]] = dis;//這段路的而距離
timee[pp[start]][pp[end]] =dis/sp;//這段路的時間
//cout<<dist[pp[start]][pp[end]]<<"--"<<timee[pp[start]][pp[end]]<<endl;
}
ans++;
}
map<string,int>::iterator it;
for(it = pp.begin(); it!=pp.end(); it++)
{
locations++;//統計共有幾個地點
//cout<<it->first<<"--"<<it->second<<endl;
}
/*for(int i=1; i<=5; i++)
{
cout<<qq[i]<<endl;
}*/
//cout<<locations<<endl;
Choose();
return 0;
}