test_12_3_4

打印全部路径

根据上一个问题,这里还是采用堆栈比较好,纯递归太繁琐了

简单的测试

下面是一个多通道图,S表示起点,E表示终点

0
1
2
3
4
S
A
B
E

初步思考

一个很简单的想法,如果走到了终点那就返回到上一个多分叉口,让多分口走其他分路试一试

所以在到终点回溯时:

  1. 为了确保该路径以后能重复用,必须重置为0
  2. 为了确保回溯后再前进时,不会再次走入相同的前进路,还需要专门的方向记录
  3. 专门的标记,确定点是否有多个前进方向

根据以上条件先写出来伪代码
p 表示当前点,Start表示起点,End 表示终点,next_search()表示下一论迭代搜索
is_multy() 表示是否为多头点,multy_count 表示多头的数量
maze[p], 表示地图maze中p点的值,p_next 表示前进或后退后的达到的点

思路:
前线搜索,如果出现出现多头点,多头点数+1,出现死区就回溯
如果一口气回溯到了起点,那么就说明这是个死地图,没有出路

如果达到终点,但是多头点数量不为0,那么说明可能又其他路线
回溯到上一个多头点,并禁止多头点向已经回溯路径搜索

死区回溯maze[p] = -1,终点回溯maze[p] = 0,前向搜索maze[p] = 2

对于最麻烦的各点搜索方向在死区回溯、终点回溯时如何修改必须,
只能一边分析,一边填补规则

if (p == End) {
		if (multy_count == 0) {
			printf("search is end, there are not any other ways");
			return 0;
		} else {
			while(!is_multy(p)) {
				maze[p] = 0;
				pop(p);
			}
			next_search(p);
		}
} else {
	multy_count += is_multy(p);
	if (is_ahead(p)) {
		push(p);
		maze[p] = 2;
		next_search(p_next);
	} else {
		if (p == Start) {
			printf("there is no way");
			return 0;
		} else {
			pop(p);
			maze[p] = -1;
			next_search(p_next);
		}
	}
}


搜索方向的变动

每个点最多有3个前进方向,但是方向的总类型为4个,再加上一个是否为多头的判断,
实际上这都需要额外存储5个数据了,那有没有更低内存消耗的办法?

回想一下之前的2进制表示,我们其实可以用一个4位的2进制数取表示前进方向
0000b == 0表示无前进点
0001b == 1表示 → \rightarrow
0010b == 2表示 ↑ \uparrow
0100b == 4表示 ← \leftarrow
1000b == 8表示 ↓ \downarrow
这样就可以只用一个ahead_statu表示前进方向和是否多头了,
不过对于这个数据需要注意初始化

而在终点回溯的过程中,想要回溯到多头点并禁止其向已经搜索过的方向再次前进
让其前进时方向有序性,这样就可以消除掉第一个前进状态即可
禁止p重复搜索,同时在终点回溯最后强行进入到下一个p_next
同时要注意到 p_statu 应该最先确定,并通过 p_statu 进行前进搜索

还有一个小问题,之前前进时判断条件之一maze[p_next]==0
但是对于这个地图来说

先走
A -0- B -1- C -4- D
终点回溯到C
那么会进入到2,3通道
并把2,3 通道当作死区 置为-1
但是实际终点回溯到B 时,还是能通过2、3通道到终点的
所以前向收缩时只要前向点不为1(障碍)、2(以访问点)即可
即前进点可为0或-1

那么补全全部细节

if (p == End) {
		if (multy_count == 0) {
			printf("search is end, there are not any other ways");
			return 0;
		} else {
			while(!is_multy(p.statu)) {
				maze[p] = 0;
				p = pop();
			}
			p.statu = change_status(p);
			if (!is_multy(p))
				multy_count -= 1;
			p_next = go_ahead(p.statu);
			next_search(p);
		}
} else {
	p.statu = get_statu(p);
	multy_count += is_multy(p);
	if (p.statu != 0) {
		push(p);
		maze[p] = 2;
		p_next = go_ahead(p.statu);
		next_search(p_next);
	} else {
		if (p == Start) {
			printf("there is no way");
			return 0;
		} else {
			p_next = pop(p);
			maze[p] = -1;
			next_search(p_next);
		}
	}
}

根据伪码补全程序即可

#include <stdio.h>

#define MAX_ROW 5
#define MAX_COL 5

/*
 * 迷宫图, 1表示障碍, 0表示路径, 只允许上下左右移动
 */

int maze[MAX_ROW][MAX_COL] = {
    0, 1, 0, 0, 0, //
    0, 1, 0, 1, 0, //
    0, 0, 0, 0, 0, //
    0, 1, 1, 1, 0, //
    0, 0, 0, 1, 0, //
};

struct point {
  int row;
  int col;
  unsigned int status;
} stack[512];
int multy_count = 0;
int top = 0;

struct point get_status(struct point p);
struct point go_ahead(struct point p);
int is_multy(struct point p);
struct point pop(void);
void push(struct point p);
void print_maze(void);
void search_path(struct point p);

int main(int argc, char *argv[]) {
  struct point p = {
      .row = 0,
      .col = 0,
      .status = 0,
  };

  search_path(p);
  return 0;

}

struct point get_status(struct point p) {
  int status = 0;
  if (p.row + 1 <= MAX_ROW - 1 && maze[p.row + 1][p.col] == 0)
    status = status + 1;
  if (p.col + 1 <= MAX_COL - 1 && maze[p.row][p.col + 1] == 0)
    status = status + 2;
  if (p.row - 1 >= 0 && maze[p.row - 1][p.col] == 0)
    status = status + 4;
  if (p.col - 1 >= 0 && maze[p.row][p.col - 1] == 0)
    status = status + 8;

  p.status = status;
  return p;
}

int is_multy(struct point p) {
  if (p.status == 1 || p.status == 2 || p.status == 4 || p.status == 8)
    return 0;
  else if (p.status < 0 || p.status >= 15) {
    printf("error");
    return -1;
  } else
    return 1;
}

struct point change_status(struct point p) {
  int status = p.status;

  if (status & 1)
    status -= 1;
  else if (status & 2)
    status -= 2;
  else if (status & 4)
    status -= 4;
  else if (status & 8)
    status -= 8;
  p.status = status;
  
  return p;
}

struct point go_ahead(struct point p) {
  struct point next_p = {.row = p.row, .col = p.col, .status = 0};
  int status = p.status;
  maze[p.row][p.col] = 2;

  if (status & 1)
    next_p.row += 1;
  else if (status & 2)
    next_p.col += 1;
  else if (status & 4)
    next_p.row -= 1;
  else if (status & 8)
    next_p.col -= 1;

  return next_p;
}

void push(struct point p) { stack[top++] = p; }  

struct point pop(void) {
  return stack[--top];
}

void print_maze(void) {
  for (int i = 0; i < MAX_ROW; i++) {
    for (int j = 0; j < MAX_COL; j++)
      printf("%d\t", maze[i][j]);
    printf("\n");
  }
  printf("**********\n");
}

void search_path(struct point p) {
  struct point next_p;

  if (p.row == MAX_ROW - 1 && p.col == MAX_COL - 1) {
    print_maze();
    if (multy_count == 0) {
      printf("search is end, there are not any other ways");
      return;
    } else {
      while (!is_multy(p)) {
        maze[p.row][p.col] = 0;
        p = pop();
      }
      p = change_status(p);
      if (!is_multy(p))
        multy_count -= 1;
      push(p);
      next_p = go_ahead(p);
      search_path(next_p);
    }
  } else {
    p = get_status(p);
    if (p.status != 0) {
      multy_count += is_multy(p);
      push(p);
      next_p = go_ahead(p);
      search_path(next_p);
    } else {
      if (p.row == 0 && p.col == 0) {
        printf("There is no way!");
        return;
      } else {
        maze[p.row][p.col] = -1;
        next_p = pop();
        search_path(next_p);
      }
    }
  }
}

但是从结果来说说是错误的

2	1	0	0	0	
2	1	0	1	0	
2	2	2	2	2	
-1	1	1	1	2	
-1	-1	-1	1	2	
**********
2	1	0	0	0	
2	1	0	1	0	
2	2	2	2	2	
-1	1	1	1	2	
-1	-1	-1	1	2	
**********

会一直重复打印这路径
将中间结果展现出来,过程差不多是

2	1	0	0	0	
2	1	0	1	0	
2	2	2	2	2	
-1	1	1	1	2	
-1	-1	-1	1	2	
**********
2	1	-1	-1	-1	
2	1	-1	1	-1	
2	2	2	2	2	
-1	1	1	1	0	
-1	-1	-1	1	0	
**********
2	1	0	0	0	
2	1	0	1	0	
2	2	2	2	2	
-1	1	1	1	2	
-1	-1	-1	1	2	
**********
2	1	-1	-1	-1	
2	1	-1	1	-1	
2	2	2	2	2	
-1	1	1	1	0	
-1	-1	-1	1	0	
**********

也就是说在死区回溯的时候,也应该用终点回溯的方式强制转向
同时为了方便理解,可以将1,2,4,8 定义位方向的宏
另外is_multy() 的判断范围弄丢了0值,无方向当然是非多头了
修改后的程序


#include <stdio.h>

#define MAX_ROW 5
#define MAX_COL 5

#define DOWN 1
#define RIGHT 2
#define UP 4
#define LEFT 8

/*
 * 迷宫图, 1表示障碍, 0表示路径, 只允许上下左右移动
 */
int maze[MAX_ROW][MAX_COL] = {
    0, 1, 0, 0, 0, //
    0, 1, 0, 1, 0, //
    0, 0, 0, 0, 0, //
    0, 1, 1, 1, 0, //
    0, 0, 0, 1, 0, //
};
struct point {
  int row;
  int col;
  int status;
} stack[512];
int multy_count = 0;
int top = 0;

struct point get_status(struct point p);
struct point go_ahead(struct point p);
int is_multy(struct point p);
int is_empty(void);
struct point pop(void);
void push(struct point p);
void print_maze(void);
void search_path(struct point p);

int main(int argc, char *argv[]) {
  struct point p = {
      .row = 0,
      .col = 0,
      .status = 0,
  };

  search_path(p);

  return 0;
}

/*
 * use the status for mark the ahead direction
 */
struct point get_status(struct point p) {
  int status = 0;

  if (p.row + 1 <= MAX_ROW - 1 &&
      (maze[p.row + 1][p.col] == 0 || maze[p.row + 1][p.col] == -1))
    status = status + DOWN;
  if (p.col + 1 <= MAX_COL - 1 &&
      (maze[p.row][p.col + 1] == 0 || maze[p.row][p.col + 1] == -1))
    status = status + RIGHT;
  if (p.row - 1 >= 0 &&
      (maze[p.row - 1][p.col] == 0 || maze[p.row - 1][p.col] == -1))
    status = status + UP;
  if (p.col - 1 >= 0 &&
      (maze[p.row][p.col - 1] == 0 || maze[p.row][p.col - 1] == -1))
    status = status + LEFT;

  p.status = status;
  return p;
}

/*
 * use the status to mark the current point is or not have multy dircetions
 * only 1 or 0 dircetions will return no(0)
 * otherwise return yes(1)
 */
int is_multy(struct point p) {
  if (p.status == 1 || p.status == 2 || p.status == 4 || p.status == 8 ||
      p.status == 0)
    return 0;
  else if (p.status < 0 || p.status >= 15) {
    printf("error");
    return -1;
  } else
    return 1;
}

int is_empty(void) { return top == 0; }

struct point change_status(struct point p) {
  int status = p.status;

  if (status & DOWN)
    status -= DOWN;
  else if (status & RIGHT)
    status -= RIGHT;
  else if (status & UP)
    status -= UP;
  else if (status & LEFT)
    status -= LEFT;

  p.status = status;
  return p;
}

struct point go_ahead(struct point p) {
  struct point next_p = {.row = p.row, .col = p.col, .status = 0};
  int status = p.status;

  maze[p.row][p.col] = 2;
  if (status & DOWN)
    next_p.row += 1;
  else if (status & RIGHT)
    next_p.col += 1;
  else if (status & UP)
    next_p.row -= 1;
  else if (status & LEFT)
    next_p.col -= 1;

  return next_p;
}

void push(struct point p) { stack[top++] = p; }

struct point pop(void) {
  return stack[--top];
}

void print_maze(void) {
  for (int i = 0; i < MAX_ROW; i++) {
    for (int j = 0; j < MAX_COL; j++)
      printf("%d\t", maze[i][j]);
    printf("\n");
  }
  printf("**********\n");
}

void search_path(struct point p) {
  struct point next_p;

  if (p.row == MAX_ROW - 1 && p.col == MAX_COL - 1) {
    /*
     * if get the end mark end as 2
     * it means that you have pass the end
     */
    maze[p.row][p.col] = 2;
    print_maze();
    if (multy_count == 0) {
      /*
       * if there are not any multy-head points
       * we have travel all the divergent path
       * all the ways from start to the end have been found
       */
      printf("search is end, there are not any other ways");
      return;
    } else {
      /*
       * there may be another divergent path to the end
       * so return to the pre multy-head point
       */
      while (is_multy(p) != 1) {
        maze[p.row][p.col] = 0;
        p = pop();
      }
      /*
       * change the multy-head point status
       * let it travel another divergent path in force
       * if it be a one-head point after changed
       * there are no any other divergent paths at this point
       */
      p = change_status(p);
      if (is_multy(p) != 1)
        multy_count -= 1;
      push(p);
      next_p = go_ahead(p);
      search_path(next_p);
    }
  } else {
    p = get_status(p);
    if (p.status != 0) {
      multy_count += is_multy(p);
      push(p);
      next_p = go_ahead(p);
      search_path(next_p);
    } else {
      while (is_multy(p) != 1 && !is_empty()) {
        maze[p.row][p.col] = -1;
        p = pop();
      }
      /*
       * if it returns to the start becase of the death area
       * it means there is no path to the end
       */
      if (p.row == 0 && p.col == 0) {
        printf("There is no way!");
        return;
      } else {
        p = change_status(p);
        if (!is_multy(p))
          multy_count -= 1;
        push(p);
        next_p = go_ahead(p);
        search_path(next_p);
      }
    }
  }
}

输出结果

2       1       0       0       0
2       1       0       1       0
2       2       2       2       2
-1      1       1       1       2
-1      -1      -1      1       2
**********
2       1       2       2       2
2       1       2       1       2
2       2       2       -1      2
-1      1       1       1       2
-1      -1      -1      1       2
**********
There is no way!

结果可用
最后那个 There is no way! 出现的原因是
在拆路口搞了一个回路,在回路中把自己堵死

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值