实现BFS以返回从顶点s到t的最小长度的路径

时间:2015-05-11 00:56:34

标签: c algorithm breadth-first-search

我正在尝试实现广度优先搜索,其中四个函数:int move1(int)int move2(int)int move3(int)int move4(int)各自从给定顶点生成新顶点,或返回-1如果无法移动,则为-1。我必须写这个函数:

struct listnode * bfspath(int s, int t)

其中struct listnode { int v, struct listnode *next };

该函数应该返回一个从顶点s开始并在顶点t结束的顶点列表,并且是从st的最小长度的路径。如果不存在路径,则返回NULL。

要存储所有当前到达的顶点,我使用高度平衡的树。队列应该是链接列表。在搜索树中,我需要存储每个已知状态以及到达它的状态。存储移动是不必要的,因为它可以通过尝试三种可能的移动来重建。利用该信息,可以以相反的顺序从起始状态到目标状态重建路径。

我知道我不应该在没有审判/错误的情况下寻求帮助,但我真的很难过。我不知道如何处理这个以及如何开始。如果有人能给我一个头脑或给我一个解释做什么,我们将不胜感激。我知道这不是一个值得深入研究的智力问题,并且不值得在stackoverflow上被问到,但我真的很感激任何帮助。

四个移动功能如下:

int move1(int i)
{  int x, y, z, newx, newy, newz;
   z = i/100000;
   x = i %1000;
   y = (i/1000)%100;
   {  newx = (x+1)%1000; newy = y; newz = z;}
   return(newz*100000 +newy*1000 + newx );
}

int move2(int i)
{  int x, y, z, newx, newy, newz;
   z = i/100000;
   x = i %1000;
   y = (i/1000)%100;
   {  newx = (x+999)%1000; newy = y; newz = z;}
   return(newz*100000 +newy*1000 + newx );
}

int move3(int i)
{  int x, y, z, newx, newy, newz;
   z = i/100000;
   x = i %1000;
   y = (i/1000)%100;
   if( (x!=0) || (y!=0))
   {  newx = x; newy = (y+1)%100; newz = z;}
   else /* (x==0) && (y==0))*/
   {newx = x; newy = y; newz = (z + 1)%4;} 
   return(newz*100000 +newy*1000 + newx );
}

int move4(int i)
{  int x, y, z, newx, newy, newz;
   z = i/100000;
   x = i %1000;
   y = (i/1000)%100;
   if( (x!=0) || (y!=0))
   {  newx = x; newy = (y+99)%100; newz = z;}
   else /* ((x==0) && (y=0)) */
   {newx = x; newy = y; newz = (z+3)%4;} 
   return(newz*100000 +newy*1000 + newx );
}

测试代码:

int main()
{  int i, j, k;
    struct listnode * path;
   for( k=0; k<10; k++ )  
   {  i = rand()%400000; j = rand()%400000;
      printf("Test %d: from %d to %d:", k, i, j);
      path = bfspath(i,j);
      if(path == NULL)
      { printf("Failed: no path found.\n"); fflush(stdout); exit(0);}
      if( path->v != i)
      {  printf("Failed.\n wrong startvertex. Should go from %d to %d; starts at %d\n",
        i,j, path->v); fflush(stdout); exit(0);
      }
      else
      {  while( path->v != j && path->next != NULL)
    {  if( path->next->v == move1(path->v)
              || path->next->v == move2(path->v)
              || path->next->v == move3(path->v)
           || path->next->v == move4(path->v) )
          path = path-> next;
       else
       {  printf("Failed.\n wrong next vertex on path: %d is not neighbor of %d\n",
            path->next->v, path->v );
          fflush(stdout); exit(0);
           } 
        }
        if( path->v != j )         
    {  printf("Failed.\n wrong final vertex; should be %d, is %d\n", j, path->v);
       fflush(stdout); exit(0);
        }
      }
      printf("Passed.\n");
   }
   printf("Tested 10 random paths\n");
   return(0);
}

1 个答案:

答案 0 :(得分:0)

我建议有一个辅助结构,也许一个数组可以做到这一点,这样你就可以存储每个节点的“父”。将BFS遍历视为生成有根生成树的一种方法。就BFS而言,每次将u,一个未访问过的顶点v的邻居添加到队列中时,就会发出v表示v是u的父亲的信息,即你​​需要找到v才能找到你。然后,一旦找到目标顶点,构建路径就是在这棵树上“回溯”。我的意思是你可以查看目标顶点的“父”,然后获得父节点的父节点,直到到达根节点,即源顶点。

如果你的边缘有重量,那么你也可以修改Dijkstra来做同样的事情。

在找到目的地之前找到路径是非常麻烦的,因为你必须要跟踪许多可能的路径,因为你事先不知道命运将显示在哪条路径上。使用父引用是一种隐式方法,用于存储从源到所有顶点的所有最短路径,而不会增加BFS的复杂性。您不构建所有路径,但这样您就可以从源顶点开始检索任何所需的路径。

您还可以构建整个BFS树,然后找到从命运到根的路径,在某种意义上它是相同的,但可能更直观。