水管工游戏
要求
如图只有两种管道,求如何摆放让管道从左上角到右下角连通?0代表树木,1~6代表管道的不同摆放方式,为了程序处理方便,将进水口在左边用1表示,上边用2表示,右边用3表示,下边用4表示。
思路
使用深度优先搜索解决,先判断当前管道的类型,然后根据进水口的方向,决定下一个管道的位置和进水口的方向。使用栈保存路径。
代码
#include <stdio.h>
#define N 5
#define M 4
int a[N][M] = {
{5, 3, 5, 3},
{1, 5, 3, 0},
{2, 3, 5, 1},
{6, 1, 1, 5},
{1, 5, 5, 4},
};
int b[N][M] = {0};
int flag = 0;
struct node
{
int x;
int y;
};
struct node stack[100];
int top = 0;
void push(int x, int y) {
stack[top].x = x;
stack[top].y = y;
top++;
}
struct node pop() {
top--;
return stack[top];
}
void print_a() {
for (int i = 0; i < N; ++i)
{
for (int j = 0; j < M; ++j)
{
printf("%3d ", a[i][j]);
}
printf("\n");
}
printf("\n");
}
void print_b() {
for (int i = 0; i < N; ++i)
{
for (int j = 0; j < M; ++j)
{
printf("%3d ", b[i][j]);
}
printf("\n");
}
printf("\n");
}
void print_s() {
for (int i = 0; i < top; ++i) {
printf("(%d %d) ", stack[i].x, stack[i].y);
}
printf("\n");
}
void dfs(int x, int y, int front) { // 1:进水口在左边 2:上 3:右 4:下
if (x == N - 1 && y == M) {
flag = 1;
print_s();
return;
}
if (x < 0 || x > N || y < 0 || y > M) {
return;
}
if (b[x][y] == 1) {
return;
}
b[x][y] = 1;
push(x, y); // 压栈
if (a[x][y] >= 5 && a[x][y] <=6 ) { // 当前管道是直管
if (front == 1) {
dfs(x, y+1, 1);
}
if (front == 2) {
dfs(x+1, y, 2);
}
if (front == 3) {
dfs(x, y-1, 3);
}
if (front == 4) {
dfs(x-1, y, 4);
}
}
if (a[x][y] >= 1 && a[x][y] <= 4) { // 当前管道是弯管
if (front == 1) {
dfs(x+1, y, 2); // 3号状态
dfs(x-1, y, 4); // 4号状态
}
if (front == 2) {
dfs(x, y+1, 1); // 1号状态
dfs(x, y-1, 3); // 4号状态
}
if (front == 3) {
dfs(x-1, y, 4); // 1号状态
dfs(x+1, y, 2); // 2号状态
}
if (front == 4) {
dfs(x, y+1, 1); // 2号状态
dfs(x, y-1, 3); // 3号状态
}
}
b[x][y] = 0;
pop(); // 出栈
}
int main()
{
dfs(0,0, 1);
if (flag == 0) {
printf("not found \n");
} else {
printf("found \n");
}
return 0;
}
总结
为什么dfs可以用递归的方式和栈的方式实现?
因为函数的调用也是通过栈的操作方式实现的,一个函数被调用时将其压栈,函数返回时出栈。