图两点间的最短路径,所有路径算法C语言实现

  • Post author:
  • Post category:其他


#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#define INFINITY      32768       //无穷大
#define MAX_VERTEX_NUM      11    //最大顶点数
typedef struct ArCell
{
   int adj;    //路径长度,对于无权图0-1-表示是否相邻,对于带权图则为权值
}ArCell;
typedef struct   //图中顶点表示主要景点,存放景点的编号、名称、简介等信息,
{
char name[30];  //名称
int num;         //编号
char introduction[100];//简介
}VertexDat;  // 定义顶点的类型
typedef struct
{
 VertexDat vexs[MAX_VERTEX_NUM];  //顶点数组
 ArCell arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM];//邻接矩阵
int vexnum,arcnum;  //顶点数,边数
}MGraph;//图的类型
MGraph *G; //图的类型,全局变量



/*   图的创建算法

输入顶点和边数,建立for循环输入景点编号,名称,简介,然后输入相邻景点的权值
并赋值给邻接矩阵所指的权值

*/
MGraph *CreatUDN(MGraph *G)//初始化图形,接受用户输入
{
 int i,j,k,w;//i,j,k,w全为循环变量
 char s[10] = "A";
#if 0 
 printf("请输入图的顶点数,弧数:");
 scanf("%d%d",&G->vexnum,&G->arcnum); //输入顶点和边数
 printf("请输入景点的编号:、名称、简介:\n"); //输入景点编号,名称,简介
 for(i=1;i<=G->vexnum;i++)
 {
 printf("景点编号:");
 scanf("%d",&G->vexs[i].num);
 printf("景点名称:");
 scanf("%s",G->vexs[i].name);
 printf("景点简介:");
 scanf("%s",G->vexs[i].introduction);
 }
 for(i=1;i<=G->vexnum;i++)
  for(j=1;j<=G->vexnum;j++)
   G->arcs[i][j].adj=INFINITY;
 printf("请输入路径长度:\n");  //输入权值(路径长度)
 for(k=1;k<=G->arcnum;k++)
 {
  printf("第%d条边:\n",k);
  printf("景点对(i,j):");   //输入相邻景点
  scanf("%d",&i);
  scanf("%d",&j);
  printf("路径长度:");  //输入相邻景点的权值
  scanf("%d",&w);
  G->arcs[i][j].adj=w; //把权值赋值给无向图G所指的邻接矩阵所指的权值
  G->arcs[j][i]=G->arcs[i][j];//  下边是可直接到达的景点间的距离,由于两个景点间距离是互相的,
                              // 所以要对图中对称的边同时赋值。
 }
#else
G->vexnum = 6;
G->arcnum = 14;
for(i=1;i<=G->vexnum;i++)
{
	G->vexs[i].num = i;
	strcpy(G->vexs[i].name, s);
	strcpy(G->vexs[i].introduction, s);
	*s += 1;
}
for(i=1;i<=G->vexnum;i++)
 for(j=1;j<=G->vexnum;j++)
  G->arcs[i][j].adj=INFINITY;

i = 1;j=2;
G->arcs[i][j].adj=1; //把权值赋值给无向图G所指的邻接矩阵所指的权值
G->arcs[j][i]=G->arcs[i][j];//  下边是可直接到达的景点间的距离,由于两个景点间距离是互相的,
							 // 所以要对图中对称的边同时赋值。
i = 2;j=1;
G->arcs[i][j].adj=1; //把权值赋值给无向图G所指的邻接矩阵所指的权值
G->arcs[j][i]=G->arcs[i][j];

i = 1;j=3;
G->arcs[i][j].adj=1; //把权值赋值给无向图G所指的邻接矩阵所指的权值
G->arcs[j][i]=G->arcs[i][j];

i = 3;j=1;
G->arcs[i][j].adj=1; //把权值赋值给无向图G所指的邻接矩阵所指的权值
G->arcs[j][i]=G->arcs[i][j];

i = 2;j=3;
G->arcs[i][j].adj=1; //把权值赋值给无向图G所指的邻接矩阵所指的权值
G->arcs[j][i]=G->arcs[i][j];

i = 3;j=2;
G->arcs[i][j].adj=1; //把权值赋值给无向图G所指的邻接矩阵所指的权值
G->arcs[j][i]=G->arcs[i][j];

i = 3;j=4;
G->arcs[i][j].adj=1; //把权值赋值给无向图G所指的邻接矩阵所指的权值
G->arcs[j][i]=G->arcs[i][j];

i = 4;j=3;
G->arcs[i][j].adj=1; //把权值赋值给无向图G所指的邻接矩阵所指的权值
G->arcs[j][i]=G->arcs[i][j];

i = 3;j=5;
G->arcs[i][j].adj=1; //把权值赋值给无向图G所指的邻接矩阵所指的权值
G->arcs[j][i]=G->arcs[i][j];

i = 5;j=3;
G->arcs[i][j].adj=1; //把权值赋值给无向图G所指的邻接矩阵所指的权值
G->arcs[j][i]=G->arcs[i][j];

i = 4;j=6;
G->arcs[i][j].adj=1; //把权值赋值给无向图G所指的邻接矩阵所指的权值
G->arcs[j][i]=G->arcs[i][j];

i = 6;j=4;
G->arcs[i][j].adj=1; //把权值赋值给无向图G所指的邻接矩阵所指的权值
G->arcs[j][i]=G->arcs[i][j];

i = 5;j=6;
G->arcs[i][j].adj=1; //把权值赋值给无向图G所指的邻接矩阵所指的权值
G->arcs[j][i]=G->arcs[i][j];

i = 6;j=5;
G->arcs[i][j].adj=1; //把权值赋值给无向图G所指的邻接矩阵所指的权值
G->arcs[j][i]=G->arcs[i][j];

#endif 
 printf("\t创建完毕!\n");
 return G;
}


/*    两点之间最短路径算法(迪杰斯特拉算法)
1.将v0到其余顶点的最短路径长度初始化为权值: Dist[i]=G->arcs[v0][vi].adj;{vi属于V-S}
2.选择vk,使得Dist[i]=min(Dist[i]|vi属于V-S)
vk为目前求的下一条从v0出发的最短路径的终点
3.将vk加入S
4.修正从v0出发到集合V-S的任一顶点vi的最短路径的长度:从v0出发到集合V-S上任一顶点vi的当前最短路径长度为Dist[i]
从v0出发,中间经过新加入S的vk,然后到达集合V-S上任一顶点vi的路径长度为:
Dist[k]+G->arcs[v][w].adj
如果Dist[k]+G->arcs[v][w].adj<Dist[i]

Dist[i]=Dist[k]+G->arcs[k][i].adj; 
重复n-1次即可求出v0到其余顶点的最短路径 

算法的时间复杂度为O(n*n).
*/
long int Dist[MAX_VERTEX_NUM];  // 辅助变量存储最短路径长度 
int p[MAX_VERTEX_NUM ][MAX_VERTEX_NUM];  //起点到终点的路径数组

void ShortestPath_DIJ(MGraph *G,int v0)// 迪杰斯特拉算法来计算出起点到终点之间的最短路径,v0为起点
{
 int v,w,i,min,x; //v,w,i,x为循环变量,min为最短长度
 int path[MAX_VERTEX_NUM];   //存放最短路径
 for(v=1;v<=G->vexnum;v++)
 {
      path[v]=0;  //假设从顶点v0到顶点v没有最短路径
  Dist[v]=G->arcs[v0][v].adj;  //将与之相关的权值放入D中存放

  for(w=1;w<=G->vexnum;w++)
      p[v][w]=0;  //设置为空路径
  if(Dist[v]<INFINITY)  //存在路径
  {
   p[v][v0]=1;  //存在标志置为一
   p[v][v]=1;   //自身到自身
  }
 }
 Dist[v0]=0;
 path[v0]=1;  //初始化v0顶点属于S集合
 for(i=1;i<=G->vexnum;i++)  //开始主循环,每一次求得v0到某个顶点的最短路径,并将其加入到S集合
 {
      min=INFINITY;   //当前所知离顶点v0的最近距离
  for(w=1;w<=G->vexnum;w++)
      if(!path[w])  //w顶点在v-s中
  if(Dist[w]<min) //w顶点离v0顶点更近
  {
  v=w;
  min=Dist[w];//最短长度给min
  }
        path[v]=1;  //离v0顶点更近的v加入到s集合
     for(w=1;w<=G->vexnum;w++)
       if(!path[w]&&(min+G->arcs[v][w].adj<Dist[w]))//更新当前最短路径及其距离
       {
        Dist[w]=min+G->arcs[v][w].adj;  // 不在s集合,并且比以前所找到的路径都短就更新当前路径 
        for(x=1;x<=G->vexnum;x++) 
          p[w][x]=p[v][x];
          p[w][w]=1;
   }
 }
 
}//ShortestPath_DIJ  end
void output(int sight1,int sight2)    // 输出函数 
{
 int a,b,c,d,q=0;
 a=sight2;    /* 将景点二赋值给a */
 if(a!=sight1)    /* 如果景点二不和景点一输入重合,则进行... */
 {
  printf("\n\t从%s到%s的最短路径是",G->vexs[sight1].name,G->vexs[sight2].name);/* 输出提示信息 */ 
  printf("\t(最短距离为 %dm.)\n\n\t",Dist[a]);  /* 输出sight1到sight2的最短路径长度,存放在D[]数组中 */
  printf("\t%s",G->vexs[sight1].name);   /* 输出景点一的名称 */
  d=sight1;      /* 将景点一的编号赋值给d */
  for(c=1;c<=MAX_VERTEX_NUM;c++)
  {
gate:;        /* 标号,可以作为goto语句跳转的位置 */
     p[a][sight1]=0;
     for(b=1;b<=MAX_VERTEX_NUM;b++)
     {
      if(G->arcs[d][b].adj<INFINITY&&p[a][b])  /* 如果景点一和它的一个临界点之间存在路径且最短路径 */
      {
       printf("-->%s",G->vexs[b].name);  /* 输出此节点的名称 */
       p[a][b]=0;
       d=b;     /* 将b作为出发点进行下一次循环输出,如此反复 */
       goto gate;
      }
     }
  }
 }
 
}
int FindInformation(MGraph *G,char a[])// 查询各景点的相关信息
{

    int i;

for(i=1;i<=G->vexnum;i++)
{
if(strcmp(G->vexs[i].name,a)==0)
break;

}
if(i==(G->vexnum+1))
{

return -1;
}
else
return G->vexs[i].num;

}
void Floyd(MGraph *G)
{
 int v,u,i,w,k,j=0,flag=1,p[MAX_VERTEX_NUM][MAX_VERTEX_NUM][MAX_VERTEX_NUM],D[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
 char A[10],B[10];
 for(v=1;v<=G->vexnum;v++)
  for(w=1;w<=G->vexnum;w++)
  {
   D[v][w]=G->arcs[v][w].adj;
   for(u=1;u<=G->vexnum;u++)
    p[v][w][u]=0;
   if(D[v][w]<INFINITY)
   {
    p[v][w][v]=1;p[v][w][w]=1;
   }
  }
 for(u=1;u<=G->vexnum;u++)
  for(v=1;v<=G->vexnum;v++)
   for(w=1;w<=G->vexnum;w++)
    if(D[v][u]+D[u][w]<D[v][w])
    {
     D[v][w]=D[v][u]+D[u][w];
     for(i=1;i<=G->vexnum;i++)
      p[v][w][i]=p[v][u][i]||p[u][w][i];
    }
 printf("\t请输入起点的景点名称:\n");
 scanf("%s",&A);
 k=FindInformation(G,A);
 if(k==-1){
 printf("\t景点不存在!\n");
 return ;
 }
 printf("\t请输入终点的景点名称:\n");
 scanf("%s",&B);
 k=FindInformation(G,B);
 if(j==-1){
 printf("\t景点不存在!\n");
 return ;
 }
 printf("%s",G->vexs[k].name);
 for(u=1;u<=G->vexnum;u++)
  if(p[k][j][u]&&k!=u&&j!=u)
   printf("-->%s",G->vexs[u].name);
 printf("-->%s",G->vexs[j].name);
 printf(" 总路线长%dm\n",D[k][j]);
}//Floyd end

int a=0;/*全局变量,用来记录每对顶点之间的所有路径的条数*/
int visited[MAX_VERTEX_NUM];/*全局数组,用来记录各顶点被访问的情况*/
int v[MAX_VERTEX_NUM];/*全局数组,用来存放路径上的各顶点*/ 
void path(MGraph *G,int i,int j,int k)
/*确定路径上第k+1个顶点的序号*/
{int s;
 if(v[k]==j)/*找到一条路径*/
 {
  a++;/*路径的条数值加1*/
  printf("第%d条:",a);
  for(s=1;s<k;s++)/*输出一条路径*/
  printf("%s->",G->vexs[v[s]].name);
  printf("%s\n",G->vexs[v[s]].name);
                       
 }
  s=1;
  while(s<=G->vexnum)
  {if(s!=i)/*保证找到的是简单路径*/
  {
  if(G->arcs[v[k]][s].adj!=INFINITY&&visited[s]==0)
  /*当vk与vs之间有边存在且vs未被访问过*/
  {visited[s]=1;/*置访问标志位为1,即已访问的*/
   v[k+1]=s;/*将顶点s加入到v数组中*/
   path(G,i,j,k+1);/*递归调用之*/
   visited[s]=0;/*重置访问标志位为0,即未访问的,以便该顶点能被重新使用*/
  }}
  s++;
  }
}
void disppath(MGraph *G,int i,int j)
{
int k;
   v[1]=i;
 for(k=1;k<=G->vexnum;k++)
 visited[i]=0;/*初始化各顶点的访问标志位,即都为未访问过的*/
 a=0;/*初始化路径的条数*/
 path(G,i,j,1);/*通过调用path函数,找到从vi到vj的所有路径并输出*/
}
void SearchAllpath(MGraph *G)/*查询两个景点间的所有路径*/
{  int i,j;
   char b[10],c[10];
printf("请输入源点景点名称:");
           scanf("%s",&b);
   i=FindInformation(G,b);
   getchar();
          if(i==-1)
      {
    printf("你输入的源点景点名称不存在!\n");
return;
}
    printf("请输入终点景点名称:");
    scanf("%s",&c);
   j=FindInformation(G,c);
     getchar();
          if(j==-1)
      {
    printf("你输入的终点景点名称不存在!\n");
return;
}
 
  printf("从%s到%s的所有游览路径有:\n",G->vexs[i].name,G->vexs[j].name);/*输出出发景点和目地景点的名称*/
  disppath(G,i,j);/*调用disppath函数,用来输出两个景点间的所有路径*/
  
 
}

char SearchMenu()  /* 查询子菜单 */
{
 char c;
 int flag;
 do{
  flag=1;
  system("cls");
  printf("\n\t\t┏━━━━━━━━━━━━━━━┑\n");
  printf("\t\t\t┃                              ┃\n");
  printf("\t\t\t┃      1、按照景点编号查询     ┃\n");
  printf("\t\t\t┃      2、按照景点名称查询     ┃\n");
  printf("\t\t\t┃      0、返回                 ┃\n");
  printf("\t\t\t┃                              ┃\n");
  printf("\t\t\t┗━━━━━━━━━━━━━━━┛\n");
  printf("\t\t\t\t请输入您的选择:");
  scanf("%c",&c);
  if(c=='1'||c=='2'||c=='0')
   flag=0;
 }while(flag);
 return c;
}
void search(MGraph *G)  /* 查询景点信息 */
{
 int num;
 int i;
 char c;
 char name[20];
 
 do
 {
  system("cls");
  c=SearchMenu();
  switch (c)
  {
  case '1':  
   system("cls");
   printf("\n\n\t\t请输入您要查找的景点编号:");
   scanf("%d",&num);
   for(i=1;i<=MAX_VERTEX_NUM;i++)
   {
    if(num==G->vexs[i].num)
    {
     printf("┏━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓\n");
     printf("┃编号┃景点名称        ┃简介                                ┃\n");
     printf("┃%-4d  %-16s┃%-56s┃\n",G->vexs[i].num,G->vexs[i].name,G->vexs[i].introduction);
     printf("┗━━┻━━━━━━━━┻━━━━━━━━━━━━━━━━━━┛\n");
     printf("\n\t\t\t按任意键返回...");
     getchar();
     getchar();
     break;
    }
   }
   if(i==MAX_VERTEX_NUM)
   {
    printf("\n\n\t\t\t没有找到!");
    printf("\n\n\t\t\t按任意键返回...");
    getchar();
    getchar();
   }
   
   break;
  case '2':
   system("cls");
   printf("\n\n\t\t请输入您要查找的景点名称:");
   scanf("%s",&name);
   for(i=1;i<=MAX_VERTEX_NUM;i++)
   {
    if(!strcmp(name,G->vexs[i].name))
    {
     printf("┏━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┓\n");
     printf("┃编号┃景点名称        ┃简介                                  ┃\n");
     printf("┃%-4d  %-16s┃%-56s┃\n",G->vexs[i].num,G->vexs[i].name,G->vexs[i].introduction);
     printf("┗━━┻━━━━━━━━┻━━━━━━━━━━━━━━━━━━━┛\n");
     printf("\n\t\t\t按任意键返回...");
     getchar();
     getchar();
     break;
    }
   }
   if(i==MAX_VERTEX_NUM)
   {
    printf("\n\n\t\t\t没有找到!");
    printf("\n\n\t\t\t按任意键返回...");
    getchar();
    getchar();
   }
   break;
  }
 }while(c!='0');
}
void Menu()
{ 
 printf("\n                                      学校导游图\n");
 printf("                           ┏━━━━━━━━━━━━━━━━━━━━┓\n");
 printf("                           ┃   1.浏览校园全景                       ┃\n");
 printf("                           ┃   2.查询图中任意两个景点间的最短路径   ┃\n");
 printf("                           ┃   3.查询图中任意两个景点间的所有路径   ┃\n");
 printf("                           ┃   4.查看景点信息                       ┃\n");
 printf("                           ┃   5.退出系统                           ┃\n");
 printf("                           ┗━━━━━━━━━━━━━━━━━━━━┛\n");
 printf("请选择:");
}
void Browser(MGraph *G)
{
 int i;
 printf("┏━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┓\n");
 printf("┃编号┃景点名称        ┃简介                                  ┃\n");
 for(i=1;i<=G->vexnum;i++)
 printf("┃%-4d┃%-16s┃%-56s┃\n",G->vexs[i].num,G->vexs[i].name,G->vexs[i].introduction);
 printf("┗━━┻━━━━━━━━┻━━━━━━━━━━━━━━━━━━━┛\n");
}


void main(void)
{
 int i;
 int v0,v1;
 G=(MGraph *)malloc(sizeof(MGraph));
 G=CreatUDN(G);
 Menu();
 scanf("%d",&i);
 while(i!=5)
 {
 switch(i)
  {
  case 1:system("cls");Browser(G);Menu();break;
  case 2:system("cls");
   printf("\n\n\t\t\t请选择起点景点:");
   scanf("%d",&v0);
   printf("\t\t\t请选择终点景点:");
   scanf("%d",&v1);
   ShortestPath_DIJ(G,v0);  /* 计算两个景点之间的最短路径 */
   output(v0,v1);     /* 输出结果 */
   Menu();break;
  case 3:system("cls");
//  Floyd(G);
  SearchAllpath(G);
  Menu();break;
  case 4:system("cls");search(G);Menu();break;
  case 5:exit(1);break;
  default:break;
  }

 scanf("%d",&i);
 }
}


转载于:https://my.oschina.net/Cw6PKk/blog/832041