DFS模板及入门题目

DFS模板

void dfs(int step){
	//判断边界
	//遍历每一种可能
		 for(i=1;i<=n;i++){
			//继续下一步 
			dfs(step+1)
		}
	//返回
}

入门例题:全排列

小明手里有三张扑克牌,需要全排列到面前三个箱子里

整体运用DFS的思想如下:

小明先把1号扑克放到1号箱子里,2号扑克放到2号箱子里,3号扑克放到3号箱子里

退回一个,此时手上有3号扑克

再退回一个,此时手上有3号,2号扑克

再将3号扑克放入2号箱子,2号扑克放入3号箱子

再退,退,退,2号扑克放1号箱子,以此类推,最后得到全排列

下面使用DFS的模板从头实现

void dfs(int step){
	//判断边界
	//遍历每一种可能
		 for(i=1;i<=n;i++){
			//继续下一步 
			dfs(step+1)
		}
	//返回
}

这里的step基本上都代表这第几个节点,本题中代表第几个箱子

判断边界:

if (step == n + 1) {
	for (int i = 1; i <= n; i++) {
		cout << li[i] << " ";
	}
	cout << endl;
	return ;
}

遍历每一种可能

for (int i = 1; i <= n; i++) {
	//如果该扑克没有被用过
	if (flag[i] == 0) {
		//将i号扑克放到step箱子里
		li[step] = i;
		//标志着i号扑克用过了
		flag[i] = 1;
		//向下一个箱子走
		dfs(step + 1);
		//全部走完了,再重置
		flag[i] = 0;
	}
}

C++整体代码:

#include 
using namespace std;

//n代表箱子(扑克)总数,flag代表该扑克是否被使用,li是排列出的队列(箱子)
int n, flag[100], li[100];

//step是小明现在站的位置
void dfs(int step) {
	//判断边界

	//因为n是递增的,step=n+1代表已经走完
	if (step == n + 1) {
		for (int i = 1; i <= n; i++) {
			cout << li[i] << " ";
		}
		cout << endl;
		return ;
	}

	//遍历每一种可能
	for (int i = 1; i <= n; i++) {
		//如果该扑克没有被用过
		if (flag[i] == 0) {
			//将i号扑克放到step箱子里
			li[step] = i;
			//标志着i号扑克用过了
			flag[i] = 1;
			//向下一个箱子走
			dfs(step + 1);
			//全部走完了,再重置
			flag[i] = 0;
		}
	}
	return ;
}

int main() {
	cin >> n;
	//从1号箱子开始
	dfs(1);
	return 0;
}

迷宫问题:HDU1312

有一个长方形的房间,上面覆盖着方形瓷砖。每个瓷砖的颜色为红色或黑色。

一个男人站在一块黑色的瓷砖上。从一块瓷砖上,他可以移动到四个相邻瓷砖之一。

但是他不能在红色瓷砖上移动,他只能在黑色瓷砖上移动。

编写一个程序来计算他可以通过重复上述动作到达的黑色瓷砖的数量。

输入

输入由多个数据集组成。数据集以包含两个正整数 W 和 H 的行开头;W 和 H 分别是 x 和 y 方向上的图块数。W 和 H 不超过 20。

数据集中还有 H 多行,每行都包含 W 个字符。每个字符表示磁贴的颜色,如下所示。

'.' - 黑色图块 '#' - 红色图块 '@' - 黑色图块上的人(在数据集中只出现一次)

输出

对于每个数据集,程序应输出一行,其中包含他从初始图块(包括自身)可以到达的图块数。

示例输入

6 9
....#.
.....#
......
......
......
......
......
#@...#
.#..#.
11 9
.#.........
.#.#######.
.#.#.....#.
.#.#.###.#.
.#.#..@#.#.
.#.#####.#.
.#.......#.
.#########.
...........
11 6
..#..#..#..
..#..#..#..
..#..#..###
..#..#..#@.
..#..#..#..
..#..#..#..
7 7
..#.#..
..#.#..
###.###
...@...
###.###
..#.#..
..#.#..
0 0

示例输出

45
59
6
13

解题思路:

题目看着挺复杂,我们先从DFS模板的思路开始

通过阅读题目,我们写出DFS的伪代码

这里的step,就是点坐标

void dfs(int x,int y){
	//判断边界
	如果该点走过了,就返回;如果超过了边界,也返回
	//遍历每一种可能
	遍历四个方向,相当于向每个方向走
	for(四个方向){
		dfs(newx,newy)
	}
	//返回
}

然后我们可以确定要使用的数据结构:

一个char型的房间room[100][100],房间的宽Wx,高Hy

可到达的方块数num

然后实现向四个方向移动的操作:

//移动的方向
int dir[4][2] = {
	{-1, 0},  //向左
	{0, -1},  //向下
	{1, 0},   //向右
	{0, 1}    ///向上
};

实现检查坐标是否越界

bool check(int x, int y) {
	return x < Wx && x >= 0 && y >= 0 && y < Hy;
}

然后在主函数中读入该数组(房间)

int x, y, dx, dy;
cin >> Wx >> Hy;
for (y = 0; y < Hy; y++) {
	for (x = 0; x < Wx; x++) {
		cin >> room[x][y];
		//起始坐标
		if (room[x][y] == '@') {
			dx = x, dy = y;
		}
	}
}

然后来实现DFS的具体功能:

//dy,dy表示结点位置
void DFS(int dx, int dy) {
	//如果是走过的,直接返回
	if (room[dx][dy] == '#' && check(dx, dy)) {
		return ;
	}
	//标记一下走过了
	room[dx][dy] = '#';

	num++;
	//向四个方向遍历
	for (int i = 0; i < 4; i++) {
		int newx = dx + dir[i][0];
		int newy = dy + dir[i][1];
		DFS(newx, newy);
	}
}

最后实现主函数的功能:

//x,y读入坐标,dx,dy代表起点
int x, y, dx, dy;
while (cin >> Wx >> Hy) {
	if (Wx == 0 && Hy == 0) {
		break;
	}
	for (y = 0; y < Hy; y++) {
		for (x = 0; x < Wx; x++) {
			cin >> room[x][y];
			//起始坐标
			if (room[x][y] == '@') {
				dx = x, dy = y;
			}
		}
	}
	num = 0;
	DFS(dx, dy);
	cout << num << endl;
}

总体程序如下:

#include 
using namespace std;
//Wx是宽,Wy是高,num是可到达的方块数
int Wx, Hy, num;

//判断坐标是否越界
bool check(int x, int y) {
	return x < Wx && x >= 0 && y >= 0 && y < Hy;
}

//房间
char room[100][100];

//移动的方向
int dir[4][2] = {
	{-1, 0},  //向左
	{0, -1},  //向下
	{1, 0},   //向右
	{0, 1}    ///向上
};

//dy,dy表示结点位置
void DFS(int dx, int dy) {
	//如果是走过的,直接返回
	if (room[dx][dy] == '#' && (check(dx, dy) == 0)) {
		return ;
	}
	//标记一下走过了
	room[dx][dy] = '#';

	num++;
	//向四个方向遍历
	for (int i = 0; i < 4; i++) {
		int newx = dx + dir[i][0];
		int newy = dy + dir[i][1];
		DFS(newx, newy);
	}
}

int main() {
	//x,y读入坐标,dx,dy代表起点
	int x, y, dx, dy;
	while (cin >> Wx >> Hy) {
		if (Wx == 0 && Hy == 0) {
			break;
		}
		for (y = 0; y < Hy; y++) {
			for (x = 0; x < Wx; x++) {
				cin >> room[x][y];
				//起始坐标
				if (room[x][y] == '@') {
					dx = x, dy = y;
				}
			}
		}
		num = 0;
		DFS(dx, dy);
		cout << num << endl;
	}
	return 0;
}

灵感来源于一本书:《算法竞赛:入门到进阶》推荐大家购买

你可能感兴趣的:(算法,算法)