遍历算法
1.DFS(Depth-First Search)
从某状态出发,不断转移状态直到无法转移,退回前一格的状态,不断反复直到结束。 DFS可用栈,但用递归实现较为简单。
1.部分和问题
给定整数a1,a2,……an,判断是否可以从中显出若干数,是他们的和恰好为k。
示例:
n=4
k=15
a={3,5,6,7}
设递归函数 (i,sum)
表示搜索到第i个数时,搜索前0,1,2……i-1个数的和sum,当搜索到某一个数时有挑选和不挑选两种选择。
注:程序的下标从0开始。
时间复杂度:O(2^n)
#include"stdio.h"
#include"stdlib.h"
#define MAX 100
int a[MAX];
int n, k;
bool dfs(int i,int sum) {
//当搜索完所有数时结束
if (i == n) return sum == k;
//分支两种情况,挑选和不挑选
if (dfs(i + 1, sum + a[i])) return true;
if (dfs(i + 1, sum)) return true;
else return false;
}
int main() {
scanf_s("%d%d", &n,&k);
for (int i = 0; i < n; i++)
scanf_s("%d", &a[i]);
if (dfs(0, 0)) puts("Yes");
else puts("No");
system("pause");
}
2. Lake Counting
有一个大仙为N*M的院子,雨后激起了水。八联通的积水被认为是连在一起的。请求出院子里总共有多少水洼?(“w”表示积水,“.”表示没有积水)
示例:N=6,M=6
ww . . . .
. w . . . .
. . .www
w . . . . .
www. . .
www. . .
建立数组field[6][6]来存储上述地图
以field[0][0]为例("-"表示在规定区域之外)
步骤一: 将所选区域标记为“.”,从而不再遍历此点
步骤二: 对field[0][0]的八个临近的区域搜索: 设置水平方向的偏移量dx,竖直方向上的偏移量dy for (int dx = -1; dx <= 1; dx++) for (int dy = -1; dy <= 1; dy++)
用二重循环遍历8个区域
步骤三: 判断是否继续递归: 当所选区域在规定区域内,且是w(积水)时继续
当一次DFS后与初始连接的w全被替换成了“.”,搜索所有区域,调用DFS的次数就是积水的个数了
时间复杂度:O(8NM)
#include"stdio.h"
#include"stdlib.h"
#define MAX 100
char field[MAX][MAX];
int M, N;w
int nums = 0;
void dfs(int x, int y) {
field[x][y] = '.';
for (int dx = -1; dx <= 1; dx++) {
for (int dy = -1; dy <= 1; dy++) {
int nx = dx + x;
int ny = dy + y;
if (nx >= 0 && nx < N&& ny >= 0 && ny < M && field[nx][ny] == 'w') dfs(nx, ny);
}
}
}
void solve() {
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
if (field[i][j] == 'w') {
dfs(i, j);
nums++;
}
}
}
}
int main() {
scanf_s("%d%d", &M, &N);
for (int i = 0; i < N; i++)
scanf_s("%s", field[i], MAX);
solve();
printf("%d\n", nums);
system("pause");
}
2.BFS(Breadth-First Search)
与深度优先遍历不同的时搜索顺序,宽度优先遍历总是先搜索距离与初始状态近的状态,因此容易用来解决最短路径,最少操作之类的问题。
BFS用队列解决问题,在C++的标准库中预置有队列
#include"queue"
using namespace std;
queue<int> que;//声明int存储类型的队列
que.push();//进队
que.front();//获得队首元素
que.pop();//队首元素出队
BFS模板:
void bfs() {
que.push(start);
…… ……
while (que.size()) {
que.front();
que.pop();
…… ……
if () {
que.push(next);
…… ……
}
}
}
Maze问题
给定大小为N*M的迷宫,求最短路径(’#’, ‘.’ , ‘S’, 'D’分别代表墙壁,通道,起点和终点)
示例:N=6,M=6
#S. . . .
##. . ##
##. . ##
##. ###
#.D###
##. ###
#include"stdio.h"
#include"stdlib.h"
#include"queue"
using namespace std;
#define INF 10000
#define MAX 100
typedef struct {
int x, y;
}Ptr;
char maze[MAX][MAX];
int sx, sy;
int dx, dy;
int M, N;
int d[MAX][MAX];
int a[4] = { -1,0,1,0 }, b[4] = { 0,1,0,-1 };
queue<Ptr> que;
void Initial() {
scanf_s("%d%d", &M, &N);
scanf_s("%d%d", &sx, &sy);
scanf_s("%d%d", &dx, &dy);
for (int i = 0; i < M; i++)
scanf_s("%s", maze[i], MAX);
for (int i = 0; i < M; i++)
for (int j = 0; j < N; j++)
//用于标记某点是否被访过
d[i][j] = INF;
}
void bfs() {
Ptr start;
start.x = sx; start.y = sy;
d[sx][sy] = 0;
que.push(start);
while (que.size()) {
Ptr p = que.front();
que.pop();
if (p.x == dx&&p.y == dy) break;
for (int i=0;i<4;i++) {
Ptr next;
int nx = p.x + a[i];
int ny = p.y + b[i];
next.x = nx;
next.y = ny;
if (nx >= 0 && nx < N&&ny >= 0 && ny < M&&d[nx][ny] == INF&&maze[nx][ny] != '#') {
que.push(next);
d[next.x][next.y] = d[p.x][p.y] + 1;
}
}
}
}
int main(){
Initial();
bfs();
printf("%d", d[dx][dy]);
system("pause");
}