用回溯法求解N皇后和迷宫问题
2014-02-15 21:39
501 查看
关于回溯法不再赘述太多,大家移步各种百科,本文介绍两种应用的实现
其典型应用之一: N皇后问题
按皇后摆放规则顺序遍历棋盘依次安放皇后,直到某一个皇后找不到合适的位置时,倒退至上一步,调整上一个皇后位置,如还不满足,继续调整再上一个,依次类推。
上述过程很容易想到用栈实现,其一组特解的代码如下
void search_solution()
{
struct position tmp;
int i = 0, j = 0;
for (; i < N; )
{
for (; j < N; j++)
{
if (detect(i,j))
{
map[i][j] = 1;
push(i,j);
break;
}
}
if (j == N)
{
tmp = pop();
i = tmp.i;
j = tmp.j;
map[i][j] = 0;
j++;
}
else
{
i++;
j = 0;
}
}
}
要找出所有解,在找到一组解后(遍历到最后一行满足条件)不退出,继续出栈,直到栈空(我的程序在设计时,直接指定了空栈时安全退出程序):
void search_all_solution()
{
struct position tmp;
int i = 0, j = 0;
while (1)
{
for (; i < N; )
{
for (; j < N; j++)
{
if (detect(i,j))
{
map[i][j] = 1;
push(i,j);
break;
}
}
if (j == N)
{
tmp = pop();
i = tmp.i;
j = tmp.j;
map[i][j] = 0;
j++;
}
else
{
i++;
j = 0;
}
}
if (i == N)
{
count++;
print_solution();
tmp = pop();
i = tmp.i;
j = tmp.j;
map[i][j] = 0;
j++;
}
}
}完整代码如下:
#include<stdio.h>
#include<string.h>
#define N 8
#define MAX_STACK_SIZE 64
struct position
{
int i, j;
};
int map
;
int empty_flag = 0;
int top = -1;
int count = 0;
struct position stack[MAX_STACK_SIZE];
void push(int i, int j)
{
top++;
stack[top].i = i;
stack[top].j = j;
empty_flag = 0;
}
struct position pop()
{
if (top == -1)
{
printf("%d solutions\n", count);
exit(0);
printf("stack is empty!\n");
empty_flag = 1;
}
return stack[top--];
}
void print_solution()
{
int i, j;
for (i = 0; i < N; i++)
{
for (j = 0; j < N; j++)
printf("%2d", map[i][j]);
printf("\n");
}
printf("\n");
}
int detect(int row, int col)
{
int i = row, j;
for (j = 0; j < N; j++)
if (map[i][j])
return 0;
j = col;
for (i = 0; i < N; i++)
if (map[i][j])
return 0;
i = row;
while (++i < N && ++j < N)
{
if (map[i][j])
return 0;
}
i = row;
j = col;
while (--i >= 0 && --j >= 0)
{
if (map[i][j])
return 0;
}
i = row;
j = col;
while (++i < N && --j >= 0)
{
if (map[i][j])
return 0;
}
i = row;
j = col;
while (--i >= 0 && ++j < N)
{
if (map[i][j])
return 0;
}
return 1;
}
void search_solution()
{
struct position tmp;
int i = 0, j = 0;
for (; i < N; )
{
for (; j < N; j++)
{
if (detect(i,j))
{
map[i][j] = 1;
push(i,j);
break;
}
}
if (j == N)
{
tmp = pop();
i = tmp.i;
j = tmp.j;
map[i][j] = 0;
j++;
}
else
{
i++;
j = 0;
}
}
}
void search_all_solution()
{
struct position tmp;
int i = 0, j = 0;
while (1)
{
for (; i < N; )
{
for (; j < N; j++)
{
if (detect(i,j))
{
map[i][j] = 1;
push(i,j);
break;
}
}
if (j == N)
{
tmp = pop();
i = tmp.i;
j = tmp.j;
map[i][j] = 0;
j++;
}
else
{
i++;
j = 0;
}
}
if (i == N)
{
count++;
print_solution();
tmp = pop();
i = tmp.i;
j = tmp.j;
map[i][j] = 0;
j++;
}
}
}
int main()
{
memset(map, 0, sizeof(map));
// search_solution();
// print_solution();
search_all_solution();
printf("%d solutions\n", count);
return 0;
}
应用之二: 走迷宫
遇到分岔路口就把分岔的坐标入栈,沿着其中一条走下去,如果无解返回分岔坐标,如此类推:
解释下程序中的矩阵,0表示路,1表示墙,走过的路径用8表示。每走一步打印一次地图可观察到程序的执行情况
#include<stdio.h>
#include<string.h>
#define ROW 7
#define COL 7
#define MAX_STACK_SIZE 32
#define UP 0
#define RIGHT 1
#define DOWN 2
#define LEFT 3
int maze[ROW][COL] = {
0,1,0,0,0,1,0,
0,1,1,1,0,0,0,
0,0,0,1,0,1,0,
0,1,1,1,0,1,1,
0,0,0,1,0,0,0,
0,1,0,1,0,1,0,
0,0,0,0,0,1,0,
};
typedef struct Point_tag
{
int row, col;
}Point;
Point stack[MAX_STACK_SIZE];
int top = -1;
int direction[4] = {0, 0, 0, 0}; //从第一个元素开始,依次标识上(0),右(1),下(2),左(3), 表示方向貌似有更好的方法
void push(Point po)
{
if (top == MAX_STACK_SIZE - 1)
printf("stack is full!\n");
else
stack[++top] = po;
}
Point pop()
{
if (top == -1)
printf("stack is empty!\n");
else
return stack[top--];
}
void print_maze()
{
int i, j;
for (i = 0; i < ROW; i++)
{
for (j = 0; j < COL; j++)
printf("%2d", maze[i][j]);
printf("\n");
}
printf("\n");
}
void count_direction(Point po, int current_dir)
{
if (po.row + 1 < ROW && maze[po.row+1][po.col] != 1 && maze[po.row+1][po.col] != 8 /*&& current_dir != UP*/)
direction[DOWN] = 1;
if (po.col + 1 < COL && maze[po.row][po.col+1] != 1 && maze[po.row][po.col+1] != 8 )
direction[RIGHT] = 1;
if (po.row - 1 >= 0 && maze[po.row-1][po.col] != 1 && maze[po.row-1][po.col] != 8)
direction[UP] = 1;
if (po.col - 1 >= 0 && maze[po.row][po.col-1] != 1 && maze[po.row][po.col-1] != 8)
direction[LEFT] = 1;
}
int num_of_dir()
{
int i = 0, count = 0;
for (; i < 4; i++)
if (direction[i] == 1)
count++;
return count;
}
int local_dir()
{
int i = 0;
for (; i < 4; i++)
if (direction[i] == 1)
return i;
}
void search(Point head , int cur_dir)
{
int numofdir, next_dir = 0, dir = cur_dir;
while (1)
{
maze[head.row][head.col] = 8;
count_direction(head, dir);
numofdir = num_of_dir();
if (numofdir == 0)
head = pop();
else
{
if (numofdir > 1)
push(head);
next_dir = local_dir();
switch (next_dir)
{
case UP: { head.row--; break; }
case RIGHT: { head.col++; /*dir = RIGHT;*/ break; }
case DOWN: { head.row++; break; }
case LEFT: { head.col--; break; }
}
}
memset(direction, 0, sizeof(int) * 4);
print_maze();
if (head.row == ROW - 1 && head.col == COL - 1)
{
maze[head.row][head.col] = 8;
print_maze();
printf("success to escape!\n");
break;
}
}
}
int main()
{
Point Head = {0, 0};
int dir = 2;
search(Head, dir);
return 0;
}
程序执行情况部分截图:
其典型应用之一: N皇后问题
按皇后摆放规则顺序遍历棋盘依次安放皇后,直到某一个皇后找不到合适的位置时,倒退至上一步,调整上一个皇后位置,如还不满足,继续调整再上一个,依次类推。
上述过程很容易想到用栈实现,其一组特解的代码如下
void search_solution()
{
struct position tmp;
int i = 0, j = 0;
for (; i < N; )
{
for (; j < N; j++)
{
if (detect(i,j))
{
map[i][j] = 1;
push(i,j);
break;
}
}
if (j == N)
{
tmp = pop();
i = tmp.i;
j = tmp.j;
map[i][j] = 0;
j++;
}
else
{
i++;
j = 0;
}
}
}
要找出所有解,在找到一组解后(遍历到最后一行满足条件)不退出,继续出栈,直到栈空(我的程序在设计时,直接指定了空栈时安全退出程序):
void search_all_solution()
{
struct position tmp;
int i = 0, j = 0;
while (1)
{
for (; i < N; )
{
for (; j < N; j++)
{
if (detect(i,j))
{
map[i][j] = 1;
push(i,j);
break;
}
}
if (j == N)
{
tmp = pop();
i = tmp.i;
j = tmp.j;
map[i][j] = 0;
j++;
}
else
{
i++;
j = 0;
}
}
if (i == N)
{
count++;
print_solution();
tmp = pop();
i = tmp.i;
j = tmp.j;
map[i][j] = 0;
j++;
}
}
}完整代码如下:
#include<stdio.h>
#include<string.h>
#define N 8
#define MAX_STACK_SIZE 64
struct position
{
int i, j;
};
int map
;
int empty_flag = 0;
int top = -1;
int count = 0;
struct position stack[MAX_STACK_SIZE];
void push(int i, int j)
{
top++;
stack[top].i = i;
stack[top].j = j;
empty_flag = 0;
}
struct position pop()
{
if (top == -1)
{
printf("%d solutions\n", count);
exit(0);
printf("stack is empty!\n");
empty_flag = 1;
}
return stack[top--];
}
void print_solution()
{
int i, j;
for (i = 0; i < N; i++)
{
for (j = 0; j < N; j++)
printf("%2d", map[i][j]);
printf("\n");
}
printf("\n");
}
int detect(int row, int col)
{
int i = row, j;
for (j = 0; j < N; j++)
if (map[i][j])
return 0;
j = col;
for (i = 0; i < N; i++)
if (map[i][j])
return 0;
i = row;
while (++i < N && ++j < N)
{
if (map[i][j])
return 0;
}
i = row;
j = col;
while (--i >= 0 && --j >= 0)
{
if (map[i][j])
return 0;
}
i = row;
j = col;
while (++i < N && --j >= 0)
{
if (map[i][j])
return 0;
}
i = row;
j = col;
while (--i >= 0 && ++j < N)
{
if (map[i][j])
return 0;
}
return 1;
}
void search_solution()
{
struct position tmp;
int i = 0, j = 0;
for (; i < N; )
{
for (; j < N; j++)
{
if (detect(i,j))
{
map[i][j] = 1;
push(i,j);
break;
}
}
if (j == N)
{
tmp = pop();
i = tmp.i;
j = tmp.j;
map[i][j] = 0;
j++;
}
else
{
i++;
j = 0;
}
}
}
void search_all_solution()
{
struct position tmp;
int i = 0, j = 0;
while (1)
{
for (; i < N; )
{
for (; j < N; j++)
{
if (detect(i,j))
{
map[i][j] = 1;
push(i,j);
break;
}
}
if (j == N)
{
tmp = pop();
i = tmp.i;
j = tmp.j;
map[i][j] = 0;
j++;
}
else
{
i++;
j = 0;
}
}
if (i == N)
{
count++;
print_solution();
tmp = pop();
i = tmp.i;
j = tmp.j;
map[i][j] = 0;
j++;
}
}
}
int main()
{
memset(map, 0, sizeof(map));
// search_solution();
// print_solution();
search_all_solution();
printf("%d solutions\n", count);
return 0;
}
应用之二: 走迷宫
遇到分岔路口就把分岔的坐标入栈,沿着其中一条走下去,如果无解返回分岔坐标,如此类推:
解释下程序中的矩阵,0表示路,1表示墙,走过的路径用8表示。每走一步打印一次地图可观察到程序的执行情况
#include<stdio.h>
#include<string.h>
#define ROW 7
#define COL 7
#define MAX_STACK_SIZE 32
#define UP 0
#define RIGHT 1
#define DOWN 2
#define LEFT 3
int maze[ROW][COL] = {
0,1,0,0,0,1,0,
0,1,1,1,0,0,0,
0,0,0,1,0,1,0,
0,1,1,1,0,1,1,
0,0,0,1,0,0,0,
0,1,0,1,0,1,0,
0,0,0,0,0,1,0,
};
typedef struct Point_tag
{
int row, col;
}Point;
Point stack[MAX_STACK_SIZE];
int top = -1;
int direction[4] = {0, 0, 0, 0}; //从第一个元素开始,依次标识上(0),右(1),下(2),左(3), 表示方向貌似有更好的方法
void push(Point po)
{
if (top == MAX_STACK_SIZE - 1)
printf("stack is full!\n");
else
stack[++top] = po;
}
Point pop()
{
if (top == -1)
printf("stack is empty!\n");
else
return stack[top--];
}
void print_maze()
{
int i, j;
for (i = 0; i < ROW; i++)
{
for (j = 0; j < COL; j++)
printf("%2d", maze[i][j]);
printf("\n");
}
printf("\n");
}
void count_direction(Point po, int current_dir)
{
if (po.row + 1 < ROW && maze[po.row+1][po.col] != 1 && maze[po.row+1][po.col] != 8 /*&& current_dir != UP*/)
direction[DOWN] = 1;
if (po.col + 1 < COL && maze[po.row][po.col+1] != 1 && maze[po.row][po.col+1] != 8 )
direction[RIGHT] = 1;
if (po.row - 1 >= 0 && maze[po.row-1][po.col] != 1 && maze[po.row-1][po.col] != 8)
direction[UP] = 1;
if (po.col - 1 >= 0 && maze[po.row][po.col-1] != 1 && maze[po.row][po.col-1] != 8)
direction[LEFT] = 1;
}
int num_of_dir()
{
int i = 0, count = 0;
for (; i < 4; i++)
if (direction[i] == 1)
count++;
return count;
}
int local_dir()
{
int i = 0;
for (; i < 4; i++)
if (direction[i] == 1)
return i;
}
void search(Point head , int cur_dir)
{
int numofdir, next_dir = 0, dir = cur_dir;
while (1)
{
maze[head.row][head.col] = 8;
count_direction(head, dir);
numofdir = num_of_dir();
if (numofdir == 0)
head = pop();
else
{
if (numofdir > 1)
push(head);
next_dir = local_dir();
switch (next_dir)
{
case UP: { head.row--; break; }
case RIGHT: { head.col++; /*dir = RIGHT;*/ break; }
case DOWN: { head.row++; break; }
case LEFT: { head.col--; break; }
}
}
memset(direction, 0, sizeof(int) * 4);
print_maze();
if (head.row == ROW - 1 && head.col == COL - 1)
{
maze[head.row][head.col] = 8;
print_maze();
printf("success to escape!\n");
break;
}
}
}
int main()
{
Point Head = {0, 0};
int dir = 2;
search(Head, dir);
return 0;
}
程序执行情况部分截图:
相关文章推荐
- 回溯法求解n皇后和迷宫问题
- 回溯法解决N皇后问题——递归与非递归求解
- 用回溯法链表求解迷宫问题
- 回溯法求解 “n 皇后 问题”——Java 实现
- 回溯法求解N-皇后问题
- 回溯法求解N皇后问题(Java实现)
- 非递归求解N皇后问题(回溯法)
- 回溯法求解N皇后问题。
- 数据结构与算法中的“递归”——用回溯法求解8皇后问题
- 回溯法求解n皇后问题
- 递归-回溯法求解8皇后问题(C)
- N皇后问题利用回溯法求解
- 迷宫问题(MazePath)的求解——利用回溯法(backtracking)
- PHP实现基于回溯法求解迷宫问题的方法详解
- 回溯算法基础---皇后问题,骑士游历,迷宫求解
- 经典算法(1)——8皇后问题求解(回溯法)
- 回溯法求解迷宫问题
- 回溯法求解N皇后问题
- 【数据结构】用回溯法求解迷宫问题
- 回溯法求解N皇后问题