例1
dfs解决迷宫问题,就是1代表障碍,0代表通过,然后问从头到尾一共有几条路径可以走到终点,这个问题同样是dfs加回溯,就是遍历每一个走过点的上下左右四个方向,直到最后走到终点再重新回溯就是return 1,把走过的还原为0,(因为走过的路都标记为1),最后return sum把顺带可以return的结果输出。
输入两个数n,m,代表迷宫的行和列,接下来输入n行m列由0,1组成的迷宫,其中1代表障碍,求从左上角到右下角的路线个数
#include<stdio.h>
#define N 1000//最大行列数
int mg[N][N];//存放迷宫图
int re[N][N];//记录之前是否走过
int n, m;//行,列
int dfs(int x, int y){//现在在(x,y)点
if(x< 0 || x > n - 1 || y < 0 || y > m - 1 || re[x][y] == 1 || mg[x][y]== 1) return 0;//走出界外或之前走过或遇到障碍
if(x ==n - 1 && y == m - 1) return 1;//走到终点
re[x][y]= 1;//该点标记为走过
int sum= 0;
sum +=dfs(x - 1, y);//向左走
sum +=dfs(x + 1, y);//向右走
sum +=dfs(x, y - 1);//向上走
sum +=dfs(x, y + 1);//向下走
re[x][y]= 0;//该点还原为没有走过
returnsum;
}
int main(){
int i,j;
while(~scanf("%d%d",&n, &m)){//输入行列
for(i= 0; i < n; i ++)
{
for(j= 0; j < m; j ++) scanf("%d", &mg[i][j]);//读入迷宫图
}
printf("%d\n",dfs(0, 0));//输出结果
}
return0;
}
例2
大致题意: 第一行输入n,m代表迷宫的行数、列数,接下来输入 n 行和 m 列迷宫(1 表示可以走,0 表示不可以走),倒数第二行代表起始点,倒数第一行代表结束点。用 “→” 连接符表示方向连接
#include <bits/stdc++.h>
using namespace std;
const int N = 30;
int n, m;
int g[N][N], d[N][N]; //g为邻接矩阵存储图,d为记录该点是否已经走过
bool flag = false;
const int dx[4] = {0, -1, 0, 1};
const int dy[4] = {-1, 0, 1, 0};
pair<int, int> start; //起始点
pair<int, int> over; //结束点
pair<int, int> after[N][N]; //记录该点往后走哪个点
void dfs(int xx, int yy){
if(xx== over.first && yy == over.second){
int a = start.first, b =start.second;
flag= true;
cout<< "(" << a << "," << b <<")->";
while(1){
autot = after[a][b];
a= t.first, b = t.second;
if(a== over.first && b == over.second){
cout<< "(" << a << "," << b <<")" << endl;
break;
}
elsecout << "(" << a << "," << b<< ")->";
}
}
int x,y;
for(inti = 0; i < 4; i++){
x= xx + dx[i], y = yy + dy[i];
if(x>= 1 && x <= n && y >= 1 && y <= m&&
d[x][y]== -1 && g[x][y] == 1){
d[x][y]= 1;
after[xx][yy]= {x, y}; //记录往后走哪个点
dfs(x,y);
d[x][y]= -1;
x= xx, y = yy;
}
}
}
int main(){
cin>> n >> m;
for(inti = 1; i <= n; i++)
for(intj = 1; j <= m; j++)
cin>> g[i][j];
cin>> start.first >> start.second;
cin>> over.first >> over.second;
memset(d,-1, sizeof d);
d[start.first][start.second]= 1;
dfs(start.first,start.second);
if(!flag)cout << -1 << endl;
return0;
}
例3
Michael喜欢滑雪百这并不奇怪, 因为滑雪的确很刺激。可是为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡或者等待升降机来载你。Michael想知道载一个区域中最长底滑坡。区域由一个二维数组给出。数组的每个数字代表点的高度。下面是一个例子
1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9
一个人可以从某个点滑向上下左右相邻四个点之一,当且仅当高度减小。在上面的例子中,一条可滑行的滑坡为24-17-16-1。当然25-24-23-...-3-2-1更长。事实上,这是最长的一条。
Input
输入的第一行表示区域的行数R和列数C(1 <= R,C <= 100)。下面是R行,每行有C个整数,代表高度h,0<=h<=10000。
Output
输出最长区域的长度。
Sample Input
5 5
1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9
Sample Output
25
AC代码:
#include<iostream>
#include<cstdio>
using namespace std;
int R, C;
int map[105][105];
int mark[105][105] = { 0 };
int dfs(int i, int j)
{
int k;
if(mark[i][j]) return mark[i][j];
if (i !=0 && map[i - 1][j] < map[i][j])
{
k =dfs(i - 1, j) + 1;
if(k> mark[i][j]) mark[i][j] = k;
}
if (i !=R - 1 && map[i + 1][j] < map[i][j])
{
k =dfs(i + 1, j) + 1;
if(k>mark[i][j]) mark[i][j] = k;
}
if (j !=0 && map[i][j - 1]<map[i][j])
{
k =dfs(i, j - 1) + 1;
if(k>mark[i][j]) mark[i][j] = k;
}
if (j !=C - 1 && map[i][j + 1]<map[i][j])
{
k =dfs(i, j + 1) + 1;
if(k>mark[i][j]) mark[i][j] = k;
}
returnmark[i][j];
}
int main()
{
int i, j,k, sum = 0;
scanf("%d%d", &R, &C);
for (i =0; i < R; i++)
{
for(j = 0; j < C; j++)
{
scanf("%d", &map[i][j]);
}
}
for (i =0; i < R; i++)
{
for(j = 0; j < C; j++)
{
k= dfs(i, j);
if (k>sum) sum = k;
}
}
cout<< sum + 1 << endl;
return 0;
}
这个题就是把每个数从四个方向都遍历一次,如果满足递减的话就接着dfs,不满足时候把这个数存起来 这个题有几个注意的问题,就是第一个要考虑好边缘临界点,就是四周的点不可以进行某些方向的移动,其次还有一点特别要注意,dfs中的if (mark[i][j]) return mark[i][j];这句话就是为了重复计算,假如从24开始的话已经算出来23,然后如果从25开始,遇到24的话直接可以找到23,而不用在遍历一次,节省了时间。