我正在尝试实现广度优先搜索,其中四个函数: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结束的顶点列表,并且是从s
到t
的最小长度的路径。如果不存在路径,则返回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);
}
答案 0 :(得分:0)
我建议有一个辅助结构,也许一个数组可以做到这一点,这样你就可以存储每个节点的“父”。将BFS遍历视为生成有根生成树的一种方法。就BFS而言,每次将u,一个未访问过的顶点v的邻居添加到队列中时,就会发出v表示v是u的父亲的信息,即你需要找到v才能找到你。然后,一旦找到目标顶点,构建路径就是在这棵树上“回溯”。我的意思是你可以查看目标顶点的“父”,然后获得父节点的父节点,直到到达根节点,即源顶点。
如果你的边缘有重量,那么你也可以修改Dijkstra来做同样的事情。
在找到目的地之前找到路径是非常麻烦的,因为你必须要跟踪许多可能的路径,因为你事先不知道命运将显示在哪条路径上。使用父引用是一种隐式方法,用于存储从源到所有顶点的所有最短路径,而不会增加BFS的复杂性。您不构建所有路径,但这样您就可以从源顶点开始检索任何所需的路径。
您还可以构建整个BFS树,然后找到从命运到根的路径,在某种意义上它是相同的,但可能更直观。