【发布时间】:2017-10-24 05:25:41
【问题描述】:
我正在尝试使用 C 中的回溯解决迷宫。要解决迷宫,请遵循以下规则:
- 你从S的位置开始,需要向E走
- 你只能继续'.'路径
- 转换所有的 '.'进入“#”,包括 S 和 E
输入由一个 m x n 矩阵组成: 输入示例:
11 11
+-+-+-+-+-+
S.|...|...|
+.+.+.+-+.+
|.|.|.....|
+.+-+-+-+.+
|...|.|...|
+.+.+.+.+-+
|.|...|.|.|
+.+-+.+.+.+
|...|.....E
+-+-+-+-+-+
预期的解决方案:
+-+-+-+-+-+
##|...|...|
+#+.+.+-+.+
|#|.|.....|
+#+-+-+-+.+
|###|.|...|
+.+#+.+.+-+
|.|###|.|.|
+.+-+#+.+.+
|...|######
+-+-+-+-+-+
我非常努力地解决它,但由于某种原因,一旦我到达迷宫中的某个点,我无法继续前进,我的程序就不会返回。它只是朝着它看到的所有方向前进'。'
我的想法是从 S 的位置开始,并在每个递归步骤中使用我们原来的位置。 如果我正在看的位置是“。”,我将从我站立的位置向所有方向走。如果那一点不是我的旧职位。
我还认为,当我回溯到一个十字路口时,我遇到了问题。例如:
+-+-+-+-+-+
##|...|...|
+#+.+.+-+.+
|#|.|.....|
+#+-+-+-+.+
|0##|.|...|
+.+#+.+.+-+
|.|###|.|.|
+.+-+#+.+.+
|..1|######
+-+-+-+-+-+
想象一下,我在位置 0。我从 1 回溯,将 # 改回 '.'。我如何发表声明说你有 2 # 种可能性回去,但你应该停下来?
我的代码:
#include <stdio.h>
#include <stdlib.h>
void *safeMalloc(int n) {
void *p = malloc(n);
if (p == NULL) {
printf("Error: malloc(%d) failed. Out of memory?\n", n);
exit(EXIT_FAILURE);
}
return p;
}
char ** readMatrix(int m,int n,int* startI,int* startJ,int* endI,int* endJ){
char **arr = safeMalloc(m*sizeof(char *));
int row;
for (row=0; row < m; row++) {
arr[row] = safeMalloc(n*sizeof(char));
}
int i,j;
for(i=0;i<m;i++){
for(j=0;j<m;j++){
scanf(" %c",&arr[i][j]);
if(arr[i][j]=='S'){
*startI=i;
*startJ=j;
}
if(arr[i][j]=='E'){
*endI=i;
*endJ=j;
}
}
getchar();
}
return arr;
}
void printNumber(char **arr,int m,int n){
int i,j;
for(i=0;i<m;i++){
for(j=0;j<n;j++){
printf("%c", arr[i][j]);
}
printf("\n");
}
}
void findPath(char** arr,int m,int n,int startI,int startJ,int endI,int endJ,int oldI,int oldJ){
int i=startI,j=startJ;
int stepsPossible=4;
//going up
if(i-1>=0){
if((arr[i-1][j]=='.') && ((i-1!=oldI) || (j!=oldJ))){
arr[i][j]='#';
oldI=i;
oldJ=j;
findPath(arr,m,n,i-1,j,endI,endJ,oldI,oldJ);
}else{
stepsPossible--;
}
}
//going right
if(j+1<n){
if((arr[i][j+1]=='.') && ((i!= oldI) || (j+1!=oldJ))){
arr[i][j]='#';
oldI=i;
oldJ=j;
findPath(arr,m,n,i,j+1,endI,endJ,oldI,oldJ);
}else{
stepsPossible--;
}
}
//going left
if(j-1>=0){
if((arr[i][j-1]=='.') && ((i!= oldI) || (j-1!=oldJ))){
arr[i][j]='#';
oldI=i;
oldJ=j;
findPath(arr,m,n,i,j-1,endI,endJ,oldI,oldJ);
}else{
stepsPossible--;
}
}
//going down
if(i+1<m){
if((arr[i+1][j]=='.') && ((i+1!= oldI) || (j!=oldJ))){
arr[i][j]='#';
oldI=i;
oldJ=j;
findPath(arr,m,n,i+1,j,endI,endJ,oldI,oldJ);
}else{
stepsPossible--;
}
}
//if the next block is E then we can stop.
if((arr[i-1][j]=='E') || (arr[i][j+1]=='E') || (arr[i][j-1]=='E') || (arr[i+1][j]=='E')){
if(arr[i-1][j]=='E'){
arr[i-1][j]='#';
}
if(arr[i][j+1]=='E'){
arr[i][j+1]='#';
}
if(arr[i][j-1]=='E'){
arr[i][j-1]='#';
}
if(arr[i+1][j]=='E'){
arr[i+1][j]='#';
}
return;
}
if(stepsPossible==0){
if(arr[i-1][j]=='#'){
arr[i][j]='.';
oldI=i;
oldJ=j;
findPath(arr,m,n,i-1,j,endI,endJ,oldI,oldJ);
}else{
return;
}
if(arr[i][j+1]=='#' ){
arr[i][j]='.';
oldI=i;
oldJ=j;
findPath(arr,m,n,i,j+1,endI,endJ,oldI,oldJ);
}else{
return;
}
if(arr[i][j-1]=='#' ){
arr[i][j]='.';
oldI=i;
oldJ=j;
findPath(arr,m,n,i,j-1,endI,endJ,oldI,oldJ);
}else{
return;
}
if(arr[i+1][j]=='#' ){
arr[i][j]='.';
oldI=i;
oldJ=j;
findPath(arr,m,n,i+1,j,endI,endJ,oldI,oldJ);
}else{
return;
}
}
}
int main()
{
int m,n;
scanf("%d %d",&m,&n);
int startI,startJ,endI,endJ;
char** arr;
arr=readMatrix(m,n,&startI,&startJ,&endI,&endJ);
findPath(arr,m,n,startI,startJ,endI,endJ,startI,startJ);
printNumber(arr,m,n);
return 0;
}
【问题讨论】:
-
你用的是什么算法?这听起来像 A* 会很好。
-
我真的没有搜索要使用的特定算法。我的想法是从 S 开始,如果我看到一个 '.',就往各个方向走。当我没有任何方向可走时,只需搜索“#”,将自己转换回“。”并将您的位置保存为 oldI,oldJ ,然后从您看到“#”的位置再次应用该功能。
-
无论如何,我不认为我应该使用任何已知的搜索算法,因为我们没有在本练习中看到它们中的任何一个。
-
除非说明说你不应该这样做,否则我看不出有任何理由不这样做。
-
如果你想自己制作一个算法,你还没有准备好实际的代码。在实施之前确保算法有效。
标签: c backtracking maze