算法题——深度优先搜索
DFS的模板
判断能否从一个点走到终点
bool dfs(v) {
if (v为终点) {
return true;
}
if (v是走过的点) {
return false;
}
//v是未走过的点
操作1:将v标记为旧点(已经走过的点)
操作2:对和v相邻的每个节点u,执行如下操作 {
if (dfs(u) == true) {
//从v到u,最终可以到终点
return true;
}
}
//从v不能走到终点
return false;
}
判断从一个点能否走到终点,如果能的话,记录路径
Node path[MAX_LEN]; //记录路径
int depth; //记录深度(走的步数)
bool dfs(v) {
if (v为终点) {
path[depth] = v;
return true;
}
if (v是走过的点) {
return false;
}
//v是未走过的点
操作1:将v标记为旧点(已经走过的点)
path[depth] = v;
++depth;
操作2:对和v相邻的每个节点u,执行如下操作 {
if (dfs(u) == true) {
//从v到u,最终可以到终点
return true;
}
}
//从v不能走到终点,回退一步,深度减1
--depth;
return false;
}
int main(){
depth = 0;
if (dfs(起点)) { //如果能走到终点,就打印路径
for (int i = 0; i < depth; i++) {
cout << path << endl;
}
}
}
例题1:城堡问题
http://bailian.openjudge.cn/practice/2815
#include<iostream>
#include<algorithm>
using namespace std;
int R, C; //行列数
int rooms[60][60]; //输入每个房间的情况:1、西墙;2、北墙;4、东墙;8、南墙
int color[60][60]; //房间是否已经走过
int maxRoomArea = 0; //最大的房间面积
int roomNum =0; //房间数量
int roomArea; //用来记录每个房间的面积j
void dfs(int i, int j) // 从room[i][j]开始进行dfs操作
{
if (color[i][j]){ //已经走过的点
return;
}
//否则是没有走过的点
++roomArea; //房间面积加1
color[i][j] = roomNum; //给这个没有走过的房间做标记(表示已经走过了)
if ((rooms[i][j] & 1) == 0) { //西边没有墙
dfs(i, j-1);
}
if ((rooms[i][j] & 2) == 0) { //北边没有墙
dfs(i-1, j);
}
if ((rooms[i][j] & 4) == 0) { //东边没有墙
dfs(i, j+1);
}
if ((rooms[i][j] & 8) == 0) {
dfs(i+1, j);
}
}
int main()
{
cin >> R >> C;
for (int i = 0; i < R; i++) {
for (int j = 0; j < C; j++) {
cin >> rooms[i][j];
color[i][j] = 0;
}
}
for (int i = 0; i < R; i++) {
for (int j = 0; j < C; j++) {
//循环遍历图中的每个点,如果color[i][j]为0,表示这里可以作为一个新房间的起点
//如果color[i][j]为1,表示这个房间已经走过了,那么就不再进行搜索了
if (!color[i][j]) {
++roomNum; //房间的数量加1
roomArea = 0; //当前房间的最大面积
dfs(i, j);
maxRoomArea = max(roomArea, maxRoomArea);
}
}
}
cout << roomNum << endl;
cout<< maxRoomArea << endl;
}
例题2:踩方块
http://bailian.openjudge.cn/practice/4103/
#include<iostream>
using namespace std;
int visited[30][50];
int ways(int i, int j, int n) {
if (n == 0){
return 1;
}
visited[i][j] = 1; // 将此步标记为1
int num = 0;
if (! visited[i][j-1]) { //向西走
num += ways(i, j-1, n-1);
}
if (! visited[i][j+1]) {
num += ways(i, j+1, n-1);
}
if(! visited[i+1][j]) {
num += ways(i+1, j, n-1);
}
visited[i][j] = 0; //离开的时候,将此步标记为未走过
return num;
}
int main(){
int n;
while (cin >> n) {
cout << ways(0, 25, n) << endl;
}
return 0;
}
例题3:Roads
http://poj.org/problem?id=1724

例题4:泉水淹没的面积
Description
有一个泉眼,由于当地的地势不均匀,有高有低,这个泉眼不断的向外溶出水来,这意味着这里在不久的将来将会一个小湖。水往低处流,凡是比泉眼地势低或者等于的地方都会被水淹没,地势高的地方水不会越过。而且又因为泉水比较弱,当所有地势低的 地方被淹没后,水位将不会上涨,一直定在跟泉眼一样的水位上。 所有的地图都是一个矩形,并按照坐标系分成了一个个小方格,Leyni知道每个方格的具体高度。我们假定当水留到地图边界时,不会留出地图外,现在他想通过这些数据分析出,将来这里将会出现一个多大面积的湖
Input
有若干组数据,每组数据的第一行有四个整数n,m,p1,p2(0<n,m,p1,p2<=1000),n和m表示当前地图的长和宽,(p1,p2)表示当前地图的泉眼位置。在n*m的矩阵里每个数字表示这每一个对应坐标的高度。
Output
输出对应地图中会有多少个格子被水充满。
Sample Input
3 5 2 3
3 4 1 5 1
2 3 3 4 7
4 1 4 1 1
Sample Output
6
#include<iostream>
#include<stack>
#include<cstring>
using namespace std;
int arr[1000][1000];
bool visit[1000][1000];
int n, m, x, y;
int h; //泉眼的高度
int sum = 0;
int dfs(int i, int j) {
if (visit[i][j]){ //已经走过
return 0;
}
visit[i][j] = true;
sum += 1;
if (i-1 >= 1 && arr[i-1][j] <= h) { //上
dfs(i-1,j);
}
if (i+1 <=n && arr[i+1][j] <= h) {
dfs(i+1, j);
}
if (j-1 >= 1 && arr[i][j-1] <= h) {
dfs(i, j-1);
}
if (j+1 <=n && arr[i][j+1] <= h) {
dfs(i, j+1);
}
return sum;
}
int main()
{
while(cin >> n >> m >> x >> y) {
memset(visit, false, sizeof(visit));
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cin >> arr[i][j];
}
}
h = arr[x][y];
dfs(x, y);
cout << sum << endl;
}
return 0;
}
如需转载,请注明文章出处,谢谢!!!
浙公网安备 33010602011771号