第四章 搜索(深度、广度搜索、全排列、走迷宫、再解炸弹人、宝岛探险、水管工游戏)
一、深度优先搜索DFS
深度优先搜索DFS的关键思想是:当下应该怎么做(每个方法都试一遍),这一步解决后,进入下一步,下一步的解决方法和这一步的解决方法是一样的
DFS的基本模型
void dfs(int step)
{
判断边界
尝试每一种可能 for(i=1;i<=n;i++)
{
继续下一步 dfs(step+1)
}
返回
}
1.1全排列

1 //输入一个数n 2 //输出1-n的全排列 3 #include <stdio.h> 4 int n, book[10], a[10]; 5 void dfs(int step) 6 { 7 int i; 8 if (step > n) 9 { 10 for (i = 1;i <= n;i++) 11 { 12 printf("%d ",a[i]); 13 } 14 printf("\n"); 15 return; 16 } 17 for (i = 1;i <= n;i++) 18 { 19 if (book[i] == 0) 20 { 21 a[step] = i; 22 book[i] = 1; 23 dfs(step+1); 24 book[i] = 0; 25 } 26 } 27 return; 28 } 29 int main() 30 { 31 scanf("%d",&n); 32 dfs(1); 33 return 0; 34 }
1.2两个三位数相加的结果是三位数,这9个数字各不相同,_ _ _ + _ _ _ = _ _ _

1 #include <stdio.h> 2 int total = 0; 3 int book[10], a[10]; 4 void dfs(int step) 5 { 6 int i; 7 if (step == 10) 8 { 9 if (100 * (a[1] + a[4]) + 10 * (a[2] + a[5]) + a[3] + a[6] == 100 * a[7] + 10 * a[8] + a[9]) 10 { 11 total++; 12 printf("%d%d%d + %d%d%d = %d%d%d\n",a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8],a[9]); 13 } 14 return; 15 } 16 for (i = 1;i < 10;i++) 17 { 18 if (book[i] == 0) 19 { 20 book[i] = 1; 21 a[step] = i; 22 dfs(step+1); 23 book[i] = 0; 24 } 25 } 26 return; 27 } 28 int main() 29 { 30 dfs(1); 31 printf("%d\n",total/2); 32 return 0; 33 }
1.3走迷宫,解救小哈

1 #include <stdio.h> 2 int n, m, map[10][10], book[10][10],endx, endy,minstep=978978; 3 void dfs(int x, int y, int step) 4 { 5 int i,tx,ty; 6 int next[4][2] = { {0,1},{1,0},{0,-1},{-1,0} }; 7 if (x == endx&&y == endy) 8 { 9 if (minstep > step) 10 minstep = step; 11 return; 12 } 13 for (i = 0;i < 4;i++) 14 { 15 tx = x + next[i][0]; 16 ty = y + next[i][1]; 17 if (tx<1 || ty<1 || tx>n || ty>m) 18 continue; 19 if (map[tx][ty] == 0 && book[tx][ty] == 0) 20 { 21 book[tx][ty] = 1; 22 dfs(tx,ty,step+1); 23 book[tx][ty] = 0; 24 } 25 } 26 return; 27 } 28 int main() 29 { 30 int i, j, startx, starty; 31 scanf("%d%d",&n,&m); 32 for (i = 1;i <= n;i++) 33 { 34 for (j = 1;j <= m;j++) 35 { 36 scanf("%d",&map[i][j]); 37 } 38 } 39 scanf("%d%d%d%d",&startx,&starty,&endx,&endy); 40 41 dfs(startx,starty,0); 42 43 printf("%d\n",minstep); 44 return 0; 45 }
二、广度优先搜索BFS
深度优先搜索DFS——递归
广度优先搜索BFS——队列
继续走迷宫

1 #include <stdio.h> 2 int n, m, endx, endy; 3 int map[10][10], book[10][10]; 4 struct node 5 { 6 int x; 7 int y; 8 int step; 9 }; 10 void bfs(int startx,int starty) 11 { 12 struct node queue[100]; 13 int head, tail; 14 int next[4][2] = { {0,1},{1,0},{0,-1},{-1,0} }; 15 int i, tx, ty, flag = 0; 16 head = 1;tail = 1; 17 queue[tail].x = startx; 18 queue[tail].y = starty; 19 queue[tail].step = 0; 20 tail++; 21 book[startx][starty] = 1; 22 while (head<tail) 23 { 24 for (i = 0;i < 4;i++) 25 { 26 tx = queue[head].x + next[i][0]; 27 ty = queue[head].y + next[i][1]; 28 if (tx<1 || ty<1 || tx>n || ty>m) 29 { 30 continue; 31 } 32 if (map[tx][ty] == 0 && book[tx][ty] == 0) 33 { 34 book[tx][ty] = 1; 35 queue[tail].x = tx; 36 queue[tail].y = ty; 37 queue[tail].step = queue[head].step + 1; 38 tail++; 39 } 40 if (tx == endx&&ty == endy) 41 { 42 flag = 1; 43 break; 44 } 45 } 46 if (flag == 1) 47 break; 48 head++; 49 } 50 printf("%d\n",queue[tail-1].step); 51 52 } 53 int main() 54 { 55 int i, j,startx,starty; 56 scanf("%d%d",&n,&m); 57 for (i = 1;i <= n;i++) 58 { 59 for (j = 1;j <= m;j++) 60 { 61 scanf("%d",&map[i][j]); 62 } 63 } 64 scanf("%d%d%d%d",&startx,&starty,&endx,&endy); 65 bfs(startx,starty); 66 return 0; 67 }
三、再解炸弹人
现在炸弹不是想放在那里就能放在那里的了,必须由小人能够走到的地方才能放置炸弹。比如下面这个例子小人默认站在(3,3)这个位置。请问放在何处最多可以消灭多个敌人。
输入
13 13 3 3
#############
#GG.GGG#GGG.#
###.#G#G#G#G#
#.......#..G#
#G#.###.#G#G#
#GG.GGG.#.GG#
#G#.#G#.#.#.#
##G...G.....#
#G#.#G###.#G#
#...G#GGG.GG#
#G#.#G#G#.#G#
#GG.GGG#G.GG#
#############
#############
#GG.GGG#GGG.#
###.#G#G#G#G#
#.......#..G#
#G#.###.#G#G#
#GG.GGG.#.GG#
#G#.#G#.#.#.#
##G...G.....#
#G#.#G###.#G#
#...G#GGG.GG#
#G#.#G#G#.#G#
#GG.GGG#G.GG#
#############
输出
将炸弹放置在(7,11)处,最多可以消灭10个敌人。

1 #include <stdio.h> 2 char map[20][20]; 3 int n, m, book[20][20]; 4 int max=0, maxx, maxy; 5 struct node 6 { 7 int x; 8 int y; 9 }; 10 int fun(int x,int y) 11 { 12 int sum = 0, k; 13 k = x; 14 while (map[k][y] != '#'&&k >= 0) 15 { 16 if (map[k][y] == 'G') 17 sum++; 18 k--; 19 } 20 k = x; 21 while (map[k][y] != '#'&&k < n) 22 { 23 if (map[k][y] == 'G') 24 sum++; 25 k++; 26 } 27 k = y; 28 while (map[x][k] != '#'&&k >= 0) 29 { 30 if (map[x][k] == 'G') 31 sum++; 32 k--; 33 } 34 k = y; 35 while (map[x][k] != '#'&&k <m) 36 { 37 if (map[x][k] == 'G') 38 sum++; 39 k++; 40 } 41 return sum; 42 } 43 void dfs(int x,int y) 44 { 45 int next[4][2] = { {0,1},{1,0},{0,-1},{-1,0} }; 46 int i,tx,ty; 47 int sum = fun(x, y); 48 if (max < sum) 49 { 50 max = sum; 51 maxx = x; 52 maxy = y; 53 } 54 for (i = 0;i < 4;i++) 55 { 56 tx = x + next[i][0]; 57 ty = y + next[i][1]; 58 if (tx < 0 || tx >= n || ty < 0 || ty >= m) 59 continue; 60 if (map[tx][ty] == '.'&&book[tx][ty] == 0) 61 { 62 book[tx][ty] = 1; 63 dfs(tx,ty); 64 } 65 } 66 return; 67 } 68 void bfs(int x,int y) 69 { 70 struct node queue[200]; 71 int head, tail,i,tx,ty,sum; 72 int next[4][2] = { {0,1},{1,0},{0,-1},{-1,0} }; 73 head = 0; 74 tail = 0; 75 queue[tail].x = x; 76 queue[tail].y = y; 77 tail++; 78 while (head < tail) 79 { 80 for (i = 0;i < 4;i++) 81 { 82 tx = queue[head].x + next[i][0]; 83 ty = queue[head].y + next[i][1]; 84 if (tx < 0 || tx >= n || ty < 0 || ty >= m) 85 continue; 86 if (map[tx][ty] == '.'&&book[tx][ty] == 0) 87 { 88 queue[tail].x = tx; 89 queue[tail].y = ty; 90 tail++; 91 sum = fun(tx, ty); 92 book[tx][ty] = 1; 93 if (sum > max) 94 { 95 max = sum; 96 maxx = tx; 97 maxy = ty; 98 } 99 } 100 } 101 head++; 102 } 103 } 104 int main() 105 { 106 int i,startx,starty; 107 scanf("%d%d%d%d",&n,&m,&startx,&starty); 108 getchar(); 109 for (i = 0;i < n;i++) 110 gets(map[i]); 111 max = fun(startx,starty); 112 maxx = startx; 113 maxy = starty; 114 book[startx][starty] = 1; 115 //dfs(startx,starty); 116 bfs(startx,starty); 117 printf("max=%d,x=%d,y=%d\n",max,maxx,maxy); 118 return 0; 119 }
四、宝岛探险

问题一
小哼降落后,所在岛屿的面积大小
输入地图和降落位置(从序号1开始)
输出降落所在位置的岛屿面积
例子
输入:
10 10 6 8
1 2 1 0 0 0 0 0 2 3
3 0 2 0 1 2 1 0 1 2
4 0 1 0 1 2 3 2 0 1
3 2 0 0 0 1 2 4 0 0
0 0 0 0 0 0 1 5 3 0
0 1 2 1 0 1 5 4 3 0
0 1 2 3 1 3 6 2 1 0
0 0 3 4 8 9 7 5 0 0
0 0 0 3 7 8 6 0 1 2
0 0 0 0 0 0 0 0 1 0
输出:
38

1 //问题一,计算面积,分别使用广度、深度搜索,进行面积计算 2 #include <stdio.h> 3 int n, m, map[50][50], book[50][50],sum; 4 int next[4][2] = { {-1,0},{1,0},{0,1},{0,-1} }; 5 6 struct node 7 { 8 int x; 9 int y; 10 }; 11 void bfs(int x,int y) 12 { 13 struct node queue[1000]; 14 int head=1, tail=1,pcur=1; 15 int i,tx,ty; 16 queue[tail].x = x; 17 queue[tail].y = y; 18 tail++; 19 book[x][y] = 1; 20 while (pcur < tail) 21 { 22 for (i = 0;i < 4;i++) 23 { 24 tx = queue[pcur].x + next[i][0]; 25 ty = queue[pcur].y + next[i][1]; 26 if (tx<1 || tx>n || ty<1 || ty>m) 27 continue; 28 if (book[tx][ty] == 0 && map[tx][ty] > 0) 29 { 30 queue[tail].x = tx; 31 queue[tail].y = ty; 32 book[tx][ty] = 1; 33 tail++; 34 } 35 } 36 pcur++; 37 } 38 printf("%d\n",tail-1); 39 } 40 41 void dfs(int x,int y) 42 { 43 int tx, ty, i, j; 44 sum++; 45 for (i = 0;i < 4;i++) 46 { 47 tx = x + next[i][0]; 48 ty = y + next[i][1]; 49 if (tx<1 || tx>n || ty<1 || ty>m) 50 continue; 51 if (book[tx][ty] == 0 && map[tx][ty] > 0) 52 { 53 book[tx][ty] = 1; 54 dfs(tx,ty); 55 } 56 } 57 return; 58 } 59 60 int main() 61 { 62 int startx, starty, i, j; 63 scanf("%d%d%d%d",&n,&m,&startx,&starty); 64 for (i = 1;i <= n;i++) 65 { 66 for (j = 1;j <= m;j++) 67 { 68 scanf("%d", &map[i][j]); 69 } 70 } 71 //bfs(startx,starty); 72 book[startx][starty] = 1; 73 dfs(startx,starty); 74 printf("%d\n",sum); 75 return 0; 76 }
问题二
小哼降落后,所在岛屿的面积大小
输入地图和降落位置(从序号1开始)
输出降落所在位置的岛屿
例子
输入:
10 10 6 8
1 2 1 0 0 0 0 0 2 3
3 0 2 0 1 2 1 0 1 2
4 0 1 0 1 2 3 2 0 1
3 2 0 0 0 1 2 4 0 0
0 0 0 0 0 0 1 5 3 0
0 1 2 1 0 1 5 4 3 0
0 1 2 3 1 3 6 2 1 0
0 0 3 4 8 9 7 5 0 0
0 0 0 3 7 8 6 0 1 2
0 0 0 0 0 0 0 0 1 0
输出:
1 2 1 0 0 0 0 0 2 3
3 0 2 0 -1 -1 -1 0 1 2
4 0 1 0 -1 -1 -1 -1 0 1
3 2 0 0 0 -1 -1 -1 0 0
0 0 0 0 0 0 -1 -1 -1 0
0 -1 -1 -1 0 -1 -1 -1 -1 0
0 -1 -1 -1 -1 -1 -1 -1 -1 0
0 0 -1 -1 -1 -1 -1 -1 0 0
0 0 0 -1 -1 -1 -1 0 1 2
0 0 0 0 0 0 0 0 1 0

1 //问题二,面积标记,分别使用广度、深度搜索,进行面积标记 2 #include <stdio.h> 3 int n, m, map[50][50], book[50][50],sum; 4 int next[4][2] = { {-1,0},{1,0},{0,1},{0,-1} }; 5 6 struct node 7 { 8 int x; 9 int y; 10 }; 11 void bfs(int x,int y) 12 { 13 struct node queue[1000]; 14 int head=1, tail=1,pcur=1; 15 int i,tx,ty; 16 queue[tail].x = x; 17 queue[tail].y = y; 18 tail++; 19 book[x][y] = 1; 20 while (pcur < tail) 21 { 22 for (i = 0;i < 4;i++) 23 { 24 tx = queue[pcur].x + next[i][0]; 25 ty = queue[pcur].y + next[i][1]; 26 if (tx<1 || tx>n || ty<1 || ty>m) 27 continue; 28 if (book[tx][ty] == 0 && map[tx][ty] > 0) 29 { 30 queue[tail].x = tx; 31 queue[tail].y = ty; 32 book[tx][ty] = 1; 33 tail++; 34 } 35 } 36 pcur++; 37 } 38 //printf("%d\n",tail-1); 39 } 40 41 void dfs(int x,int y) 42 { 43 int tx, ty, i, j; 44 sum++; 45 for (i = 0;i < 4;i++) 46 { 47 tx = x + next[i][0]; 48 ty = y + next[i][1]; 49 if (tx<1 || tx>n || ty<1 || ty>m) 50 continue; 51 if (book[tx][ty] == 0 && map[tx][ty] > 0) 52 { 53 book[tx][ty] = 1; 54 dfs(tx,ty); 55 } 56 } 57 return; 58 } 59 void print_map() 60 { 61 int i, j; 62 for (i = 1;i <= n;i++) 63 { 64 for (j = 1;j <= m;j++) 65 { 66 if (book[i][j]) 67 { 68 map[i][j] = -1; 69 } 70 printf("%d ",map[i][j]); 71 } 72 printf("\n"); 73 } 74 } 75 int main() 76 { 77 int startx, starty, i, j; 78 scanf("%d%d%d%d",&n,&m,&startx,&starty); 79 for (i = 1;i <= n;i++) 80 { 81 for (j = 1;j <= m;j++) 82 { 83 scanf("%d", &map[i][j]); 84 } 85 } 86 //bfs(startx,starty); 87 book[startx][starty] = 1; 88 dfs(startx,starty); 89 //printf("%d\n",sum); 90 print_map(); 91 return 0; 92 }

1 //问题二,面积标记,分别使用广度、深度搜索,进行面积标记 2 //dfs、着色法 3 #include <stdio.h> 4 int n, m, map[50][50], book[50][50],sum; 5 int next[4][2] = { {-1,0},{1,0},{0,1},{0,-1} }; 6 7 void dfs(int x,int y,int color) 8 { 9 int tx, ty, i, j; 10 sum++; 11 map[x][y] = color; 12 for (i = 0;i < 4;i++) 13 { 14 tx = x + next[i][0]; 15 ty = y + next[i][1]; 16 if (tx<1 || tx>n || ty<1 || ty>m) 17 continue; 18 if (book[tx][ty] == 0 && map[tx][ty] > 0) 19 { 20 book[tx][ty] = 1; 21 dfs(tx,ty,color); 22 } 23 } 24 return; 25 } 26 void print_map() 27 { 28 int i, j; 29 for (i = 1;i <= n;i++) 30 { 31 for (j = 1;j <= m;j++) 32 { 33 printf("%d ",map[i][j]); 34 } 35 printf("\n"); 36 } 37 } 38 int main() 39 { 40 int startx, starty, i, j; 41 scanf("%d%d%d%d",&n,&m,&startx,&starty); 42 for (i = 1;i <= n;i++) 43 { 44 for (j = 1;j <= m;j++) 45 { 46 scanf("%d", &map[i][j]); 47 } 48 } 49 //bfs(startx,starty); 50 book[startx][starty] = 1; 51 dfs(startx,starty,-1); 52 53 print_map(); 54 return 0; 55 }
问题三
求出地图中小岛个数
例子
输入:
10 10
1 2 1 0 0 0 0 0 2 3
3 0 2 0 1 2 1 0 1 2
4 0 1 0 1 2 3 2 0 1
3 2 0 0 0 1 2 4 0 0
0 0 0 0 0 0 1 5 3 0
0 1 2 1 0 1 5 4 3 0
0 1 2 3 1 3 6 2 1 0
0 0 3 4 8 9 7 5 0 0
0 0 0 3 7 8 6 0 1 2
0 0 0 0 0 0 0 0 1 0
输出:
-1 -1 -1 0 0 0 0 0 -2 -2
-1 0 -1 0 -3 -3 -3 0 -2 -2
-1 0 -1 0 -3 -3 -3 -3 0 -2
-1 -1 0 0 0 -3 -3 -3 0 0
0 0 0 0 0 0 -3 -3 -3 0
0 -3 -3 -3 0 -3 -3 -3 -3 0
0 -3 -3 -3 -3 -3 -3 -3 -3 0
0 0 -3 -3 -3 -3 -3 -3 0 0
0 0 0 -3 -3 -3 -3 0 -4 -4
0 0 0 0 0 0 0 0 -4 0

五、水管工游戏
题目输入:5行4列的图,0表示树木
5 4
5 3 5 3
1 5 3 0
2 3 5 1
6 1 1 5
1 5 5 4
输出:
(1,1) (1,2) (2,2) (3,2) (3,3) (3,4) (4,4) (5,4)
不可能时输出impossible
使用深度搜索,在每个方格内dfs需要的参数为,方格坐标x,y,水管的进口(如下图数字表示),以及改方格的水管类型,改方格是否使用过

问题一:找到通道

1 //水管工,深度搜索 2 #include <stdio.h> 3 int map[50][50], book[50][50]; 4 int n, m,flag; 5 void dfs(int x,int y,int open) 6 { 7 if (x == n&&y == m+1) 8 { 9 flag = 1; 10 return; 11 } 12 if (x<1 || x>n || y<1 || y>m) 13 return; 14 if (book[x][y]) 15 return; 16 book[x][y] = 1; 17 if (map[x][y] > 0 && map[x][y] <= 4) 18 { 19 if (open == 1) 20 { 21 dfs(x-1,y,4); 22 dfs(x+1,y,2); 23 } 24 if (open == 2) 25 { 26 dfs(x,y+1,1); 27 dfs(x,y-1,3); 28 } 29 if (open == 3) 30 { 31 dfs(x-1,y,4); 32 dfs(x+1,y,2); 33 } 34 if (open == 4) 35 { 36 dfs(x, y - 1, 3); 37 dfs(x, y + 1, 1); 38 } 39 } 40 if (map[x][y] == 5 || map[x][y] == 6) 41 { 42 if (open == 1) 43 dfs(x,y+1,1); 44 if (open == 2) 45 dfs(x+1,y,2); 46 if (open == 3) 47 dfs(x,y-1,3); 48 if (open == 4) 49 dfs(x-1,y,4); 50 } 51 book[x][y] = 0; 52 return; 53 } 54 int main() 55 { 56 int i, j; 57 scanf("%d%d",&n,&m); 58 for (i = 1;i <= n;i++) 59 { 60 for (j = 1;j <= m;j++) 61 scanf("%d",&map[i][j]); 62 } 63 dfs(1,1,1); 64 if (flag) 65 printf("路径存在\n"); 66 else 67 printf("路径不存在\n"); 68 return 0; 69 }
问题二:输出路径

1 //水管工,深度搜索 2 #include <stdio.h> 3 int map[50][50], book[50][50]; 4 int n, m,flag; 5 struct node 6 { 7 int x; 8 int y; 9 }s[100]; 10 int top = 0; 11 void dfs(int x,int y,int open) 12 { 13 int i; 14 if (x == n&&y == m+1&&open==1) 15 { 16 flag = 1; 17 for (i = 0;i < top;i++) 18 { 19 printf("(%d,%d) ", s[i].x, s[i].y); 20 } 21 printf("\n"); 22 return; 23 } 24 if (x<1 || x>n || y<1 || y>m) 25 return; 26 if (book[x][y]) 27 return; 28 book[x][y] = 1; 29 s[top].x = x; 30 s[top].y = y; 31 top++; 32 if (map[x][y] > 0 && map[x][y] <= 4) 33 { 34 if (open == 1) 35 { 36 dfs(x-1,y,4); 37 dfs(x+1,y,2); 38 } 39 if (open == 2) 40 { 41 dfs(x,y+1,1); 42 dfs(x,y-1,3); 43 } 44 if (open == 3) 45 { 46 dfs(x-1,y,4); 47 dfs(x+1,y,2); 48 } 49 if (open == 4) 50 { 51 dfs(x, y - 1, 3); 52 dfs(x, y + 1, 1); 53 } 54 } 55 if (map[x][y] == 5 || map[x][y] == 6) 56 { 57 if (open == 1) 58 dfs(x,y+1,1); 59 if (open == 2) 60 dfs(x+1,y,2); 61 if (open == 3) 62 dfs(x,y-1,3); 63 if (open == 4) 64 dfs(x-1,y,4); 65 } 66 book[x][y] = 0; 67 top--; 68 return; 69 } 70 int main() 71 { 72 int i, j; 73 scanf("%d%d",&n,&m); 74 for (i = 1;i <= n;i++) 75 { 76 for (j = 1;j <= m;j++) 77 scanf("%d",&map[i][j]); 78 } 79 dfs(1,1,1); 80 if (flag) 81 { 82 printf("路径存在\n"); 83 //加在这里是错误的,原因是,递归函数变化过程中,会把结果的s重新改变 84 //应在递归函数结束时,直接打印出来 85 /*for (i = 0;i < top;i++) 86 { 87 printf("(%d,%d) ", s[i].x, s[i].y); 88 } 89 printf("\n");*/ 90 } 91 else 92 printf("路径不存在\n"); 93 return 0; 94 }