基于多最短路径Dijkstra算法和动态规划的导航系统

        本系统的核心功能主要实现了两点间的多条最短路径规划及遍历全图的最短路径规划,其中,分别使用了基于单路径改进的Dijkstra算法基于状态压缩的动态规划算法,代码如下:

#define INF 1000 
#define MAX_vertex 50
#define MAX_key 15
#define LEN 50
#define password "xyq"

#include<windows.h>
#include<iostream>
#include<fstream>
#include<conio.h>
#include<vector>
using namespace std;

typedef struct VNode  //点
{
    char sight[LEN];//顶点名称
    char spot_info[LEN];//顶点信息
} VNode;

typedef struct Map
{
    VNode vex[MAX_vertex];//顶点信息
    int matrix[MAX_vertex][MAX_vertex];//邻接矩阵
    int vernum, edgnum;//图的顶点和边
} Map;

void menu_welcome();//菜单
void menu_user();
void view_map();
void login();//密码
void clear();

//功能函数
void createMap(Map &map);//基于邻接矩阵创建无向网
void Show_short(Map &map);//功能5
void shortPath(Map &map, int v0, vector<int> path[], int weight[MAX_vertex]); // Dijkstra
void All_Show_short(Map &map);//功能6
void all_shortpath(int M, Map &map, int weight[MAX_key][1<<(MAX_key-1)]);//动态规划
bool isVisited(Map &map,bool visited[]);
void Information(Map &map);//功能1
void Info_dail(Map &map);//功能2
void show_near_Matrix(Map &map);//邻接矩阵
int get_paths_num(int v0, int v, vector<int> p[]);//求最短路径条数
void print_path(int v0, int v, int len, Map &map, int cur[], vector<int> p[]); // 输出路径

int main()
{
    system("title Campus navigation system");
    system("color E1") ;
    menu_welcome();  login();  

    int choose;
    Map map;
    createMap(map);
    while(clear(),menu_user(),scanf("%d",&choose)!=EOF)
    {
        system("cls");
        switch(choose)
        {
            case 0: menu_welcome();  cout<<"\n\n\tEnd";
                    for(int i=0; i < 6; i++){  Sleep(500);cout<<".";  }  exit(0);
            case 1:Information(map);break;
            case 2:Info_dail(map);break;
            case 3:view_map();break;
            case 4:show_near_Matrix(map);break;
            case 5:Show_short(map);break;
            case 6:All_Show_short(map);break;
            default:cout<<"\n\tplease enter the number between 0 and 6 ...___\n\t";getch();
        }
    }

    return 0;
}

void clear()
{
    system("cls");
    fflush(stdin);
}

void login()//密码
{
    char key[MAX_key],c;
    int i;
    cout << "\n\tPlease enter your password -> ";
    while(1)
    {
    	fflush(stdin);
    	i=0;
    	while((c=getch())!=13)
		{
			if(c==8&&i>0)
			{
				printf("\b \b");//清除*号和错符
				i--;
				continue;
			}
			if(c!=8)
			{
				key[i++]=c;
				putchar('*');
			}
	    }
	    key[i]='\0';
		if(strcmp(password,key)==0)
        {
            cout << "\n\n\tCorrect...\n\n ";
            cout << "\tPlease press any key to continue...\n";
            getch();system("color F0") ;system("cls");
			return ;
        }
        else
            cout << "\n\n\tone more time-> ";
    }//重复输入密码直到正确
}

void menu_welcome()//菜单
{
    printf("\n\t______________________________________\n");
    printf("\n\t________Thanks for your using_________\n");
    printf("\n\t_______________NDKY___________________\n");
    printf("\n\t_________Navigation System____________\n");
    printf("\n\t______________________________________\n");
    printf("\n\t");
}

void menu_user()
{
    printf("\n\t___________________________________________________________\n");
    printf("\n\t________Please select The features you want to use_________\n\n");
    printf("\n\t________1) View all location information___________________\n");
    printf("\n\t________2) View the introduction of a location_____________\n"); 
    printf("\n\t________3) View specific images____________________________\n");
    printf("\n\t________4) View the adjacency matrix_______________________\n");
    printf("\n\t________5) Choosing a Travel Route_________________________\n");
    printf("\n\t________6) View the shortest path to all locations_________\n");
    printf("\n\t________0) Exit the system_________________________________\n");
    printf("\n\t___________________________________________________________\n");
    printf("\n\t");
}

void view_map()
{
    printf("\n\t                     |___---School Map---__|                  \n");
    printf("\t                                                                 \n");
    printf("\t         _____________|6 Art_Design|________________|7 Machinery|\n");
    printf("\t         |                   |                             |\n");
    printf("\t|5 Life_Medicine|____________|_________|8 library|_________|\n");
    printf("\t         |                   |                             |\n");
    printf("\t   |4 Landscape|______|9 Renlai_Humans|_________|10 Info_Engineering|\n");
    printf("\t         |                   |                             |\n");
    printf("\t         |                   |                             |\n");
    printf("\t|3 Administrative|______|          |                 |          |\n");
    printf("\t         |              |11 build_A|_________________|12 build_B|\n");
    printf("\t     |        |_________|          |                 |          |\n");
    printf("\t     |        |              |                             |     \n");
    printf("\t     |2 Dining|         |          |                 |          |\n");
    printf("\t     |        |_________|13 build_C|_________________|14 build_D|\n");
    printf("\t     |        |         |          |                 |          |\n");
    printf("\t         |                   |                             |\n");
    printf("\t         |                   |                             |\n");
    printf("\t     |1 Aca_Ex_Center |______|____________|0 Gate|_________|\n");
    printf("\n\t");
    printf("\n_________________________________________________________________________________\n");
    cout << "\n\tPress any key to return..." << endl;
    getch();
}

void createMap(Map &map)//基于邻接矩阵创建无向网
{
    fstream file;

    file.open("data.txt");
    if(!file)
    {
        cout << "\tFile reading failure ~ ";
        getch();  exit(0);
    }
    for (int i = 0; i < map.vernum;i++)
        file >> map.vex[i].sight >> map.vex[i].spot_info;
    file.close();

    file.open("map.txt");
    if(!file)
    {
        cout << "\tFile reading failure ~ ";
        getch();  exit(0);
    }

    file >> map.vernum >> map.edgnum;

    for (int i = 0; i < map.vernum; i++)
        for (int j = 0; j < map.vernum; j++)
        {
            if(i==j)
                map.matrix[i][j] = 0;
            else
                map.matrix[i][j] = INF;
        }

    for (int i = 0; i < map.edgnum; i++)
    {
        int v1, v2, num;
        file >> v1 >> v2 >> num;
        map.matrix[v1][v2] = num;
        map.matrix[v2][v1] = num;
    }

    file.close();
}

void Show_short(Map &map)
{
    fflush(stdin);
    int v0, v1;
    vector<int> path[MAX_vertex];    // 最短路径下标
    int weight[MAX_vertex];//到某顶点的最短路径权值

    int flag = 1;
    while(flag)
    {
        cout << "\n\tPlease enter the start and end point...   eg(1 2)\n\n\t";
        cin >> v0 >> v1;
        if(v0<0||v0>map.vernum||v1<0||v1>map.vernum)
            cout << "\n\twrong,please check again..." << endl;
        else
            flag = 0;
    }
    printf("\n\t___________________________________________________________\n");
    cout << "\n\tThe shortest path from " << map.vex[v0].sight << " to " << map.vex[v1].sight << " is" << endl;
    shortPath(map, v0, path, weight);

    if(weight[v1] == INF)
        cout << "\tsorry,There is no road to reach it\n";
    else
    {
        int cur[MAX_vertex];
        int c = get_paths_num(v0, v1, path);
        cout <<"\n\tThere are "<<c<<" shortest paths:" << endl;
        print_path(v0, v1, 0, map, cur, path);
        cout <<"\n\tLength : "<< weight[v1]<<"m"<<endl;
        printf("\n\t___________________________________________________________\n");
    }
    cout << endl;
    cout << "\n\n\tPress any key to return..." << endl;
    getch();
}

void All_Show_short(Map &map)
{
    fflush(stdin);
    vector<int> path;    // 最短路径下标
    int weight[MAX_key][1<<(MAX_key-1)];//到某顶点的最短路径权值
    bool Flag[MAX_vertex]={false};
    static const int M = 1 << (map.vernum - 1);
    int v0, pioneer = 0, min = INF, S = M-1, temp ;

    int flag = 1;
    while(flag)
    {
        cout << "\n\tPlease enter the starting point...   eg(1)\n\n\t";
        cin >> v0 ;
        if(v0<0||v0>map.vernum)
            cout << "\n\twrong,please check again..." << endl;
        else flag = 0;
    }
    
    printf("\n\t________________________________________________________________________\n");
    cout << "\n\tThe shortest path from " << map.vex[v0].sight<<" is " << endl<<endl;

    all_shortpath(M, map, weight);
    
    path.push_back(0);
    while(!isVisited(map,Flag))
    {
        for(int i=1; i<map.vernum;i++)
        {
            if(Flag[i] == false && (S &(1<<(i-1))) != 0)
            {
                if(min > map.matrix[i][pioneer] + weight[i][S^(1<<(i-1))])
                {
                    min = map.matrix[i][pioneer] + weight[i][S^(1<<(i-1))] ;
                    temp = i;
                }
            }
        }
        pioneer = temp;
        path.push_back(pioneer);
        Flag[pioneer] = true;
        S = S ^ (1<<(pioneer - 1));
        min = INF;
    }

    int count = 0;cout<<"\t";
    vector<int>::iterator  it;
    for(it = path.begin();*it!=v0;it++);
    for(it; it != path.end();it++)
        {cout<<map.vex[*it].sight<<"->";
            count++;if(count%6==0)cout<<"\n\t\n\t";}
    for(it =path.begin(); *it != v0;it++)
        {cout<<map.vex[*it].sight<<"->";
            count++;if(count%6==0)cout<<"\n\t\n\t";}
    cout<<map.vex[v0].sight;

    printf("\n\t________________________________________________________________________\n");
    cout << "\n\n\tPress any key to return..." << endl;
    getch();
}

bool isVisited(Map &map,bool visited[])//判断结点是否都以访问,不包括0号结点
{
    for(int i = 1 ; i<map.vernum;i++)
        if(visited[i] == false)
            return false;
    return true;
}

void shortPath(Map &map, int v0, vector<int> path[], int weight[MAX_vertex])//Dijkstra
{
    int v, w;
    bool flag[MAX_vertex];//顶点是否确定,初始化为false
    for (v = 0; v < map.vernum; v++)
    {
        weight[v] = map.matrix[v0][v];
        path[v].clear();
        path[v].push_back(v0);
        flag[v] = false;
    }
    flag[v0] = true;
    weight[v0] = 0;
    path[v0].clear();

    for (int i = 1; i < map.vernum; i++)
    {
        int min = INF;
        for (w = 0; w < map.vernum; w++)
            if(flag[w]==false && weight[w]<min)
            { v=w;min=weight[w]; }
        flag[v] = true;
        for (w = 0; w < map.vernum; w++)
        {
            if(flag[w]==false && min+map.matrix[v][w]<weight[w])
            {
                weight[w] = min + map.matrix[v][w];
                path[w].clear();
                path[w].push_back(v);
            }
            else if(flag[w]==false && min+map.matrix[v][w]==weight[w])
            {
                weight[w] = min + map.matrix[v][w];
                path[w].push_back(v);
            }
        }
    }
}

int get_paths_num(int v0, int v, vector<int> p[])//求最短路径条数
{
    int count = 0;
    if(v0==v)return 1;
    for (int i = 0; i < p[v].size(); i++)
        count += get_paths_num(v0, p[v][i], p);
    return count;
}

void print_path(int v0, int v,int len, Map &map,int cur[],vector<int> p[]) // 输出路径
{
    cur[len] = v;
    if(v==v0)
    {
        cout << "\n\t";
        for (int i = len; i > 0;i--)
            printf("%s->", map.vex[cur[i]].sight);
        printf("%s\n", map.vex[cur[0]].sight);
        return;
    }
    for (int i = 0; i < p[v].size(); i++)
        print_path(v0, p[v][i],len+1,map,cur, p);
}

void all_shortpath(int M, Map &map,  int weight[MAX_key][1<<(MAX_key-1)])//动态规划
{
    for(int i = 0 ; i < map.vernum ;i++)
        weight[i][0] = map.matrix[i][0];

    //求解weight[i][j],先跟新列在更新行
    for(int j = 1 ; j < M ;j++)
    {
        for(int i = 0 ; i < map.vernum ;i++ )
        {
            weight[i][j] = INF;
            //如果集和j(或状态j)中包含结点i,则不符合条件退出
            if( ((j >> (i-1)) & 1) == 1)  { continue; }

            for(int k = 1 ; k < map.vernum ; k++)
            {
                if( ((j >> (k-1)) & 1) == 0)  { continue; }
                if( weight[i][j] > map.matrix[i][k] + weight[k][j^(1<<(k-1))])
                {  weight[i][j] = map.matrix[i][k] + weight[k][j^(1<<(k-1))];  }
            }
        }
    }
}

void Information(Map &map)
{
    cout << endl<<endl;
    printf("\tThere are %d locations here:", map.vernum);
    printf("\n\t___________________________________________________________\n\n");
    for(int i=0;i<map.vernum; i++){
		printf("\t%d\t%s\n",i,map.vex[i].sight);
	}
    printf("\t___________________________________________________________\n");
    cout << "\n\n\tPress any key to return..." << endl;
    getch();
}

void Info_dail(Map &map)
{
    int num;
    cout << endl<<endl;
    printf("\tPlease enter the location you want to know: eg(0) \n");
    printf("\n\t* Enter -1 to return to the main menu\n\t");
    while(cin>>num,num!=-1)
    {
        if(num < 0 || num > map.vernum-1)
        {
            printf("\tnot exist...\n\tplease check again...( %d ~ %d )\t",0,map.vernum-1);
            getch();
            continue;
        }
        printf("\t_______________________________________________________________\n\n");
        printf("\t%d  %s : %s\n", num, map.vex[num].sight,map.vex[num].spot_info);
        printf("\t_______________________________________________________________\n\n\t");
    }
    cout << "\n\n\treturn..." << endl;
    cout << "\n\tPress any key to return..." << endl;
    getch();
}

void show_near_Matrix(Map &map)//邻接矩阵
{
    printf("\n\t___________________________________________________________________________________________________________________________\n\n");
    for (int i = 0; i < map.vernum; i++)
    {
        for (int j = 0; j < map.vernum; j++)
            if(map.matrix[i][j]!=INF)
                printf("\t%d ", map.matrix[i][j]);
            else
                printf("\tINF");
        printf("\n");
    }
    printf("\n\t___________________________________________________________________________________________________________________________\n");
    cout << "\n\n\tPress any key to return..." << endl;
    getch();
}

目录

一、系统概述

2、系统总体功能设计

2.1 功能模块设计

2.2 数据结构分析设计

3、主要函数详细设计

3.1 login 函数的详细设计

3.2 Information函数的详细设计

3.3 Info_dail函数的详细设计

3.4 show_near_Matrix 函数的详细设计

3.5 print_path 函数的详细设计

3.6 Show_short函数的详细设计

3.7 ShortPath 函数的详细设计

3.8 All_Show_short函数的详细设计

3.9 all_shortpath 函数的详细设计

4、系统功能实现效果

4.1登录系统

4.2进入系统菜单

4.3功能执行

4.3.1 功能1——查看所有地点(View all location information)

4.3.2 功能2——某一地点的介绍(View the introduction of a location)

4.3.3 功能3——显示校园地图(View specific images)

4.3.4 功能4——查看邻接矩阵(View the adjacency matrix)

4.3.5 功能5——选择最短路径(Choosing a Travel Route)

4.3.6 功能6——浏览全部地点最短路径(View the shortest path to all locations)

4.4退出系统(0 Exit the system)

5、总结

5.1总结

5.2不足与展望

6、附录


一、系统概述

        本系统的编译环境为Visual Studio Code,使用C/C++混合编程,通过多最短路径Dijkstra算法及动态规划构建校园导航系统,涵盖本校南校区15个地点,共包含六种功能,分别为:1) 查看所有地点 ; 2) 某一地点的介绍 ; 3) 显示校园地图 ; 4) 查看邻接矩阵 ; 5) 选择最短路径 ; 6) 浏览全部地点最短路径

       首先我利用文件读取操作读取校园北区的地点信息(data.txt)和相关距离信息(map.txt),接着通过结构体存储顶点和邻接矩阵信息,由于可能存在多条最短路径,我们在Dijkstra算法的基础上引入动态数组存储前置节点。为简便计算同时压缩状态,我对局部节点用二进制表示,基于动态规划算法实现全图浏览最短路径的功能。

       同时,为增强人机交互性及用户体验,我增加了窗口换色、登录界面、密码保护、输入提示及样例展示、输入错误的警告、独立功能页面、等待退出等服务。

       本系统使用的校园地图可视化如下:

2、系统总体功能设计

2.1 功能模块设计

函数层次概要图

系统所用函数库及自定义

函数库

自定义

#include<windows.h>

#include<iostream>

#include<fstream>

#include<conio.h>

#include<vector>

#define INF 1000

#define MAX_vertex 50

#define MAX_key 15

#define LEN 50

#define password "xyq"        

系统自定义函数

自定义函数

功能

createMap

基于邻接矩阵创建无向网

Show_short

实现两点间最短路径

shortPath

求解两点最短路径

All_Show_short

输出全图遍历最短路径

all_shortpath

求解全图遍历最短路径

isVisited

记录顶点是否被访问

Information

查看所有地点

Info_dail

查看地点详细信息

show_near_Matrix

查看邻接矩阵

get_paths_num

求解两点间最短路径数量

print_path

输出两点间最短路径

       由于本系统的编译环境Visual Studio Code不支持直接中文输入,会涉及到很多英文,由于较多,我们将对应翻译表放置附录。

2.2 数据结构分析设计

       我们定义结构体Vnode存储顶点信息,包含地点名称及地点介绍;定义结构体Map存储邻接矩阵,用vernum和edgnum分别表示图的顶点和边,具体如下:

结构体定义

顶点信息

邻接矩阵

typedef struct VNode 

{

    char sight[LEN];

    char spot_info[LEN];

} VNode;

typedef struct Map

{

    VNode vex[MAX_vertex];

    int matrix[MAX_vertex][MAX_vertex];

    int vernum, edgnum;

} Map;

       本系统利用自定义函数CreateMap读取data.txt和map.txt文件信息,构建邻接矩阵无向网,避免重复输入及Visual Studio Code环境不能直接输入中文的问题,若打不开文件会显示“File reading failure ~”。

3、主要函数详细设计

3.1 login 函数的详细设计

       为保护用户的隐私性,我加入了输入密码的函数login,且通过“*”覆盖,对其密码进行不可视化。其会无限次输入密码,不断与password比较,直到输入正确才能进入系统,输入错误会提示“one more time ->”,让用户再输入一次,其具体流程图如下:

Login函数主体功能设计

while((c=getch())!=13)

{

     if(c==8&&i>0)

     {

          printf("\b \b");

               //清除*号和错符

           i--;

           continue;

     }

     if(c!=8)

     {

           key[i++]=c;

           putchar('*');

     }

}

3.2 Information函数的详细设计

此函数实现功能1,遍历输出所有地点及对应序号,具体如下:

Information函数主体功能设计

for(int i=0;i<map.vernum; i++){

        printf("\t%d\t%s\n",i,map.vex[i].sight);

    }

3.3 Info_dail函数的详细设计

        此函数实现功能2,查看某一地点详细信息,具体如下:

Info_dail函数主体功能设计

while(cin>>num,num!=-1)

{

       if(num < 0 || num > map.vernum-1)

       {

              printf("\tnot exist...\n\tplease check again...( %d~ %d )\t",0,map.vernum-1);

              getch();

              continue;

       }

       …

       printf("\t%d  %s : %s\n", num,    map.vex[num].sight,map.vex[num].spot_info);

       …

}

3.4 show_near_Matrix 函数的详细设计

        此函数实现功能4,遍历输出完整邻接矩阵,两点不可达时显示为INF,这边展示主体代码:

Show_near_Matrix函数主体功能设计

for (int i = 0; i < map.vernum; i++)

    {

        for (int j = 0; j < map.vernum; j++)

            if(map.matrix[i][j]!=INF)

                printf("\t%d ", map.matrix[i][j]);

            else

                printf("\tINF");

        printf("\n");

    }

3.5 print_path 函数的详细设计

       此函数实现输出所有最短路径功能,通过迭代从终点开始倒序,迭代到起点终止,输出动态数组p中的所有节点,实现多条最短路径的输出。用cur记录局部最短路径,len表示cur的长度,初始化为0,为方便存储,我们引入动态数组p表示每个节点存储的多个前驱节点,这里以结点v0为例,绘制具体结构如下:

Print_path函数主体功能设计

void print_path(int v0, int v,int len, Map &map,int cur[],vector<int> p[])

{

    cur[len] = v;

    if(v==v0)

    {

        cout << "\n\t";

        for (int i = len; i > 0;i--)

            printf("%s->", map.vex[cur[i]].sight);

        printf("%s\n", map.vex[cur[0]].sight);

        return;

    }

    for (int i = 0; i < p[v].size(); i++)

        print_path(v0, p[v][i],len+1,map,cur, p);

}

3.6 Show_short函数的详细设计

       此函数实现功能 5,输出多条最短路径,具体流程图如下:

Show_short 函数主体功能设计

       while(flag)

    {

        … cin >> v0 >> v1;

        if(v0<0||v0>map.vernum||v1<0||v1>map.vernum)

            cout << "\n\twrong,please check again..." << endl;

        else  flag = 0;

}

       …

       map.vex[v1].sight << " is" << endl;

       shortPath(map, v0, path, weight);

    if(weight[v1] == INF)

        cout << "\tsorry,There is no road to reach it\n";

    else

    {

        int c = get_paths_num(v0, v1, path);  …

        print_path(v0, v1, 0, map, cur, path);  …       

    }

3.7 ShortPath 函数的详细设计


       这是本系统的核心代码之一,在Dijkstra算法进行改进,实现多最短路径的输出,即功能5。由于需要记录多个前驱节点,原始算法的一维数组显然满足不了,需要进行升维,我们不妨将其定义为vector类(vetor<int> path[])。函数流程图具体如下:

 图9 shortPath 函数流程图

下面我们列出详细求解过程(完整代码查看文件即可):

1) 首先初始化path[ ],weight[ ],并将v0标记为True,表示已遍历:

 for (v = 0; v < map.vernum; v++)

    {

        weight[v] = map.matrix[v0][v];

        path[v].clear();

        path[v].push_back(v0);

        flag[v] = false;

    }

//标记并初始化

flag[v0] = true;

weight[v0] = 0;

path[v0].clear();

2)  假设现有n个节点,那么我们需要查找n-1次,初始化min后遍历每个尚未被标记的节点寻找最小距离,找到后标记,进入下一循环,我们添加讨论相等路径实现多最短路径记录,若满足相等,则直接入栈;若找到更优路径,则清空原记录的所有节点,更新为现最优节点,具体代码如下:

for (int i = 1; i < map.vernum; i++)

    {

        int min = INF;

        for (w = 0; w < map.vernum; w++)

            if(flag[w]==false && weight[w]<min)

            { v=w;min=weight[w]; }

        flag[v] = true;

        for (w = 0; w < map.vernum; w++)

        {

            if(flag[w]==false && min+map.matrix[v][w]<weight[w])

            {

                weight[w] = min + map.matrix[v][w];

                path[w].clear();  path[w].push_back(v);

            }

            else if(flag[w]==false && min+map.matrix[v][w]==weight[w])

            {

                weight[w] = min + map.matrix[v][w];

                path[w].push_back(v);

            }

        }

    }

3.8 All_Show_short函数的详细设计


       此函数实现功能6,输出遍历全图的最短路线图,具体流程图如下:

       获取最优路径时,我们根据动态规划公式反向找出最短路径节点,以地点0序号为基础找出全局最优最短路径;在遍历输出时分成两段,实现起点的变化。

下面分别列出这两部分的主体代码

获取最优路径

while(!isVisited(map,Flag))

    {

        for(int i=1; i<map.vernum;i++)

        {

            if(Flag[i] == false && (S &(1<<(i-1))) != 0)

            {

                if(min > map.matrix[i][pioneer] + weight[i][S^(1<<(i-1))])

                {

                    min = map.matrix[i][pioneer] + weight[i][S^(1<<(i-1))] ;

                    temp = i;

                }

            }

        }

        pioneer = temp;

        path.push_back(pioneer);

        Flag[pioneer] = true;

        S = S ^ (1<<(pioneer - 1));

        min = INF;

    }

变化输出

vector<int>::iterator  it;

    for(it = path.begin();*it!=v0;it++);

    for(it; it != path.end();it++)

        {cout<<map.vex[*it].sight<<"->";

            count++;if(count%6==0)cout<<"\n\t\n\t";}

    for(it =path.begin(); *it != v0;it++)

        {cout<<map.vex[*it].sight<<"->";

            count++;if(count%6==0)cout<<"\n\t\n\t";}

    cout<<map.vex[v0].sight;    }

3.9 all_shortpath 函数的详细设计

       这是本系统的核心代码之一,基于动态规划寻找遍历全图的最短路径。已知动态规划方程:

        其中,v0表示起点,d(i,v)表示从顶点i出发经过v中的顶点有且只有一次,最后返回出发点的路径长度。

       下面我们假设出发点为序号0地点,对动态规划过程进行可视化,具体流程图如下:

       接着需要将d(i,v)用代码存储,我们通过weight[N][M]来表示,其中,N表示城市个数,M表示集合数量,即M=2^(N-1)。同时我们对V进行状态压缩,将地点转化为二进制再用十进制数表示,比如用1(0001)表示{1},用3(0011)表示{1,2},用15(1111)表示{1,2,3,4}。

       代码体现: 1) 用 1<<(i-1) 表示第i个城市;

                            2) 通过 (V>>(i-1)&1)==1 判断V中第i位是否为1

                            3) 通过 V=V^(1<<(i-1)) 剔除V中的i元素

all_shortpath 功能设计

for(int i = 0 ; i < map.vernum ;i++)

        weight[i][0] = map.matrix[i][0];

    for(int j = 1 ; j < M ;j++)

    {

        for(int i = 0 ; i < map.vernum ;i++ )

        {

            weight[i][j] = INF;

            if( ((j >> (i-1)) & 1) == 1)  continue;

            for(int k = 1 ; k < map.vernum ; k++)

            {

                if( ((j >> (k-1)) & 1) == 0)   continue;

                if( weight[i][j] > map.matrix[i][k] + weight[k][j^(1<<(k-1))])

                   weight[i][j] = map.matrix[i][k] + weight[k][j^(1<<(k-1))];

            }

        }

    }

4、系统功能实现效果

4.1登录系统

       根据系统提示输入密码,

         这边默认密码设置为“xyq”, 注意输入时只显示“*”,用户是看不到自己输入的密码的,可以保护隐私,且支持回车操作,我们先输入错误密码,


       系统提示在输入一次,现在我们输入正确密码,按任意键继续,


       进入功能菜单,且界面颜色变白,如图所示有六个功能,按0退出,我们先输入不在0 ~ 6 之间的数字,


       提示输入0 ~ 6 的数字,按任意键继续,我们回到主菜单,

 

4.2进入系统菜单

4.3功能执行

4.3.1 功能1——查看所有地点(View all location information)

       我们输入1,进入功能1的菜单,显示如下,按任意键返回,

4.3.2 功能2——某一地点的介绍(View the introduction of a location)


       我们输入2,进入功能2的菜单,显示如下,提示输入-1返回主菜单,

        试试输入想查询的地点,

         接着我们输入不在地点序号范围内的数字100,提示重新输入,

         我们输入-1退出,提示按任意键返回,

​​​​​​​

4.3.3 功能3——显示校园地图(View specific images)

我们输入3,进入功能3的菜单,显示如下,按任意键返回,

4.3.4 功能4——查看邻接矩阵(View the adjacency matrix)

       我们输入4,进入功能4的菜单,显示如下,按任意键返回,

4.3.5 功能5——选择最短路径(Choosing a Travel Route)


       我们输入 0 5,显示共有1条最短路线,最短路线,路线长度为30m, 

       下面我们对路线进行可视化

        我们输入 0 7,显示共有2条最短路线,最短路线,路线长度为30m,   

下面我们对路线进行可视化

4.3.6 功能6——浏览全部地点最短路径(View the shortest path to all locations)


       我们输入6,进入功能6的菜单,显示如下,输入任意起点,


       我们输入-1,显示输入错误,提示重新输入,

       我们输入0作为起始点,输出全图路径,为保证页面美观,输出时每隔五个换一行,如下:
下面我们对路线进行可视化

4.4退出系统(0 Exit the system)

       我们输入0,退出系统,End后面的“.”每隔0.5s输出,最终退出系统

5、总结

5.1总结

       本系统选取Dijkstra算法计算最短路径,并在原算法的基础上进行改进,在Dijkstra算法的基础上引入动态数组存储前置节点,实现多最短路径输出。选取动态规划解决全图最短路径,为简便计算同时压缩状态,我对局部节点用二进制表示,基于动态规划算法实现全图浏览最短路径的功能。

       灵活运用 #define 使编程更加规范化,同时简化代码;用到文件操作可以省去我们再自己输入的操作,提高程序效率。

       同时,为增强人机交互性及用户体验,我增加了窗口换色、登录界面、密码保护、输入提示及样例展示、输入错误的警告、独立功能页面、等待退出等服务,使用Sleep、system(“cls”)、getch()、system(“title XX”)、system(“color XX”)、等函数增加观赏性。

     该程序在实现教科书上规定的功能的基础上增添了几个新功能,且界面美观,与用户交互性好,考虑情况较为全面。且该程序采取模块化编程可以后期继续进行功能开发。

5.2不足与展望

       本系统选取的Dijkstra算法能够求出从起点到其余每个结点的最短路径,但需要遍历所有的路径和结点,计算复杂度比较大。同时我们发现,在该算法实现过程中找最小边的步骤,可以运用优先队列来缩短这个过程,进行Dijkstra的二叉堆优化。

       本系统选取的动态规划算法计算复杂度较大,最多只支持15个地点(即本文参考校园地点的数量),有待改进。

       代码可以更加简洁精进,继续开发别的功能。

6、附录

       本系统使用C/C++语言混合编写,采用Visual Studio Code环境运行。运行需三个文件,分别为Dijkstra_navigation.cpp、data.txt、map.txt,下面为材料说明表:

 支撑材料说明表

文件名

说明

翻译表

翻译

Data.txt

地点信息

Map.txt

邻接矩阵

 翻译表

英文

翻译

View all location information

查看所有地点

View the introduction of a location

某一地点的介绍

View specific images

显示校园地图

View the adjacency matrix

查看邻接矩阵

Choosing a Travel Route

选择最短路径

View the shortest path to all location

浏览全部地点最短路径

Exit the system  

退出系统

Gate

大门

Aca_Ex_Center

学术交流中心

Dining

食堂

Administrative

行政用房

Landscape

景观园林

Life_Medicine

生命医学学院

Art_Design

设计艺术学院

Machinery

机械建筑学院

library

图书馆

Renlai_Humans

人文和法商学院

Info_Engineering

信息工程学院

build_A

教学楼A

build_B

教学楼B

build_C

教学楼C

build_D

教学楼D

data.txt

校门口 学校1号门,处于封闭状态

学术交流中心 神秘地带

食堂 一号食堂,共两层

行政用房 处理学生报销、选课、借教室等事务

景观园林 散步观赏的好去处

生命医学学院 包含生物技术等专业

设计艺术学院 包含多媒体可视化等专业

机械建筑学院 包含电气自动化等专业

图书馆 学习地带,经常座无虚席

人文和法商学院 文科专业集中点,包含法学、汉语言文学等专业

信息工程学院 包含软件工程等专业

教学楼A 基础学院管辖

教学楼B 基础学院管辖

教学楼C 基础学院管辖

教学楼D 基础学院管辖

map.txt

15 25

0 1 12

0 13 11

0 14 13

1 2 10

1 13 13

2 3 7

2 11 7

2 13 5

3 11 5

3 4 7

4 5 8

4 9 5

5 6 10

5 8 13

6 7 5

6 9 18

7 8 8

7 10 8

8 10 10

9 10 5

9 11 4

10 12 7

11 13 2

12 14 2

13 14 5

猜你喜欢

转载自blog.csdn.net/qq_63761366/article/details/128546596