啊哈 算法 Java_《啊哈!算法》-第 4 章:万能的搜索

深度优先搜索

深度优先搜索(Depth First Search, DFS)。理解深度优先搜索的关键在于解决“当下该如何做”。至于“下一步该如何做”则与“当下该如何做”是一样的。下面的代码就是深度优先搜索的基本模型:

void dfs(int step) {

// 判断边界

// 尝试每一种可能

for (i = 1; i <= n; i++) {

// 继续下一步

dfs(step + 1);

}

// 返回

}

发明深度优先算法的是 John E. Hopcroft(约翰·霍普克洛特)和 Robert E. Tarjan(罗伯特·陶尔扬)。

使用深度优先搜索解决问题

[][][] + [][][] = [][][] 问题

6270f7ac5df0e8b4d1c7040e7dc76b87.png

#include

#define NUM 10

int a[NUM], book[NUM];

void dfs(int step) {

int i;

if (step == 10) {

if (

(a[1] * 100 + a[2] * 10 + a[3]) + (a[4] * 100 + a[5] * 10 + a[6]) == a[7] * 100 + a[8] * 10 + a[9]

) {

for (i = 1; i <= 9; i++) {

printf("%d", a[i]);

}

printf("\n");

}

}

for (i = 1; i <= 9; i++) {

if (book[i] == 0) {

a[step] = i;

book[i] = 1;

dfs(step + 1);

book[i] = 0;

}

}

}

int main(void) {

dfs(1);

return 0;

}

全排列

#include

#define NUM 10

int a[NUM], book[NUM], n;

void dfs(int step) {

int i;

if (step == n + 1) {

for (i = 1; i <= n; i++) {

printf("%d", a[i]);

}

printf("\n");

return;

}

for (i = 1; i <= n; i++) {

if (book[i] == 0) {

a[step] = i;

book[i] = 1;

dfs(step + 1);

book[i] = 0;

}

}

}

int main(void) {

scanf("%d", &n);

dfs(1);

return 0;

}

解救小哈

方向感不好的小哈在迷宫里迷路了。小哼得知后便立即去解救小哈。假如小哼已经知道迷宫的地图和小哈的位置,且迷宫中有障碍物,小哼是不能够到达的。那么求出小哼怎样走能够最快的找到小哈?

地图由一个二维数组组成,用 0 表示可到达的位置,2 表示不可到达的位置:

int a[4][4] = {

{0, 0, 2, 0},

{0, 0, 0, 2},

{0, 2, 0, 0},

{0, 0, 0, 0}

};

得知小哈的位置在(2, 2)。

#include

int a[4][4] = {

{0, 0, 2, 0},

{0, 0, 0, 2},

{0, 2, 0, 0},

{0, 0, 0, 0}

};

int book[4][4], tx, ty, min = 9999;

int forward[4][2] = {

{-1, 0},

{0, 1},

{1, 0},

{0, -1}

};

void dfs(int x, int y, int step) {

int i;

// 边界

if (x == 2 && y == 2) {

if (step < min) {

min = step;

}

// 返回

return;

}

// 尝试每一种可能

for (i = 0; i < 4; i++) {

tx = x + forward[i][0];

ty = y + forward[i][1];

if (tx >= 0 || tx < 4 || ty >=0 || ty < 4) {

if (a[tx][ty] == 0 && book[tx][ty] == 0) {

book[tx][ty] = 1;

// 继续下一步

dfs(tx, ty, step + 1);

book[tx][ty] = 0;

}

}

}

}

int main(void) {

int i, j;

for (i = 0; i < 4; i++)

for(j = 0; j < 4; j++)

book[i][j] = 0;

book[0][0] = 1;

dfs(0, 0, 0);

printf("%d\n", min);

return 0;

}

炸弹人

#include

#define NUM 13

char a[NUM][NUM] = {

{'#','#','#','#','#','#','#','#','#','#','#','#','#'},

{'#','G','G','.','G','G','G','#','G','G','G','.','#'},

{'#','#','#','.','#','G','#','G','#','G','#','G','#'},

{'#','.','.','.','.','.','.','.','#','.','.','G','#'},

{'#','G','#','.','#','#','#','.','#','G','#','G','#'},

{'#','G','G','.','G','G','G','.','#','.','G','G','#'},

{'#','G','#','.','#','G','#','.','#','.','#','.','#'},

{'#','#','G','.','.','.','G','.','.','.','.','.','#'},

{'#','G','#','.','#','G','#','#','#','.','#','G','#'},

{'#','.','.','.','G','#','G','G','G','.','G','G','#'},

{'#','G','#','.','#','G','#','G','#','.','#','G','#'},

{'#','G','G','.','G','G','G','#','G','.','G','G','#'},

{'#','#','#','#','#','#','#','#','#','#','#','#','#'}

};

int book[NUM][NUM];

int max = 0, amount, p, q;

int direction[4][2] = {

{-1, 0},

{0, 1},

{1, 0},

{0, -1}

};

int getNum(int i, int j) {

// 杀上边的怪

int x = i;

int y = j;

int num = 0;

while (a[x][y] != '#') {

if (a[x][y] == 'G') {

num += 1;

}

x -= 1;

}

// 杀右边的怪

x = i;

y = j;

while (a[x][y] != '#') {

if (a[x][y] == 'G') {

num += 1;

}

y += 1;

}

// 杀下边的怪

x = i;

y = j;

while (a[x][y] != '#') {

if (a[x][y] == 'G') {

num += 1;

}

x += 1;

}

// 杀左边的怪

x = i;

y = j;

while (a[x][y] != '#') {

if (a[x][y] == 'G') {

num += 1;

}

y -= 1;

}

return num;

}

void dfs(int x, int y) {

int i;

// 边界判断

amount = getNum(x, y);

if (amount > max) {

max = amount;

p = x;

q = y;

}

// 尝试每一步

for (i = 0; i < 4; i++) {

int tx = x + direction[i][0];

int ty = y + direction[i][1];

if (tx > 1 || tx < NUM || ty > 1 || ty < NUM) {

if (a[tx][ty] == '.' && book[tx][ty] == 0) {

book[tx][ty] = 1;

// 尝试下一步

dfs(tx, ty);

}

}

}

}

int main(void) {

book[3][3] = 1;

dfs(3, 3);

printf("(%d, %d) %d\n", p, q, max);

return 0;

}

使用广度优先搜索解决问题

炸弹人

#include

#define NUM 13

char a[NUM][NUM] = {

{'#','#','#','#','#','#','#','#','#','#','#','#','#'},

{'#','G','G','.','G','G','G','#','G','G','G','.','#'},

{'#','#','#','.','#','G','#','G','#','G','#','G','#'},

{'#','.','.','.','.','.','.','.','#','.','.','G','#'},

{'#','G','#','.','#','#','#','.','#','G','#','G','#'},

{'#','G','G','.','G','G','G','.','#','.','G','G','#'},

{'#','G','#','.','#','G','#','.','#','.','#','.','#'},

{'#','#','G','.','.','.','G','.','.','.','.','.','#'},

{'#','G','#','.','#','G','#','#','#','.','#','G','#'},

{'#','.','.','.','G','#','G','G','G','.','G','G','#'},

{'#','G','#','.','#','G','#','G','#','.','#','G','#'},

{'#','G','G','.','G','G','G','#','G','.','G','G','#'},

{'#','#','#','#','#','#','#','#','#','#','#','#','#'}

};

int book[NUM][NUM];

int max = 0;

int direction[4][2] = {

{-1, 0},

{0, 1},

{1, 0},

{0, -1}

};

int getNum(int i, int j) {

// 杀上边的怪

int x = i;

int y = j;

int num = 0;

while (a[x][y] != '#') {

if (a[x][y] == 'G') {

num += 1;

}

x -= 1;

}

// 杀右边的怪

x = i;

y = j;

while (a[x][y] != '#') {

if (a[x][y] == 'G') {

num += 1;

}

y += 1;

}

// 杀下边的怪

x = i;

y = j;

while (a[x][y] != '#') {

if (a[x][y] == 'G') {

num += 1;

}

x += 1;

}

// 杀左边的怪

x = i;

y = j;

while (a[x][y] != '#') {

if (a[x][y] == 'G') {

num += 1;

}

y -= 1;

}

return num;

}

int main(void) {

int i, j, tx, ty, amount, p, q;

for (i = 0; i < NUM; i++)

for (j = 0; j < NUM; j++)

book[i][j] = 0;

// 初始化队列

struct node {

int x;

int y;

} que[1000];

int head, tail;

head = 0;

tail = 0;

// 设定?人的位置

book[3][3] = 1;

que[tail].x = 3;

que[tail].y = 3;

tail++;

// 广度优先搜索模型

while (head < tail) {

for (i = 0; i < 4; i++) {

tx = que[head].x + direction[i][0];

ty = que[head].y + direction[i][1];

// 判断是否跑出地图外

if (tx > 1 || tx < NUM || ty > 1 || ty < NUM) {

// 判断该位置是否可用到达

if (a[tx][ty] == '.' && book[tx][ty] == 0) {

que[tail].x = tx;

que[tail].y = ty;

book[tx][ty] = 1;

tail++;

// 计算杀敌数量

amount = getNum(tx, ty);

if (amount > max) {

max = amount;

p = tx;

q = ty;

}

}

}

}

// 每一个点尝试完毕后,需要出队

head++;

}

printf("(%d, %d) %d\n", p, q, max);

return 0;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值