利用深度优先搜索(dfs)来解决迷宫问题
一.深度优先搜索(dfs)
1.什么叫dfs
深度优先搜索类似于树的先序遍历;
是利用栈或者递归的方式实现的,体现出了后进先出的特点;
通俗来说就是一次访问一条路,一直朝着一个方向探索,直到遇到死路退回到前一个分支,继续探索;
一般来说,深度搜索解决的问题主要为寻求所有解和连通性。
2.遍历过程
(1)从图中某个初始顶点v出发,首先访问初始顶点v。
(2)然后依次从v的未被访问的邻接点w,再从w出发进行深度优先遍历,直到图中所有与v有路径相通的的顶点都被访问过为止。
3.算法设计
解决问题:
(1)如何确定一个顶点是否访问过?
设置一个visited[]全局数组,
visited[i]=0表示顶点i没有访问;
visited[i]=1表示顶点i已经访问过。
(在图中也可以修改图本身来实现)
4.dfs算法模板
void dfs(int s)
{
if(找到解了)
{
相应的操作;
return ;
}
尝试每一种可能
{
if(满足条件)
{
标记走过;
进行下一步dfs;
回溯一步; //恢复原状态
}
}
}
二.例题示范
棋盘问题
(1)问题描述:
在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案C。
(2)输入:
输入含有多组测试数据。
每组数据的第一行是两个正整数,n k,用一个空格隔开,表示了将在一个n*n的矩阵内描述棋盘,以及摆放棋子的数目。 n <= 8 , k <= n
当为-1 -1时表示输入结束。
随后的n行描述了棋盘的形状:每行有n个字符,其中 # 表示棋盘区域, . 表示空白区域(数据保证不出现多余的空白行或者空白列)。
(3)输出:
对于每一组数据,给出一行输出,输出摆放的方案数目C (数据保证C<2^31)。
(4)样例输入:
2 1
#.
.#
4 4
…#
…#.
.#…
#…
-1 -1
(5)样例输出
2
1
#include<stdio.h>
#include<string.h>
int n,k;
char map[10][10];
int sum;
int visited[10];
void dfs(int y,int t)
{
if(t==k)
{
sum++;
return ;
}
//满足条件,次数加1,返回;
if(y<=n)
dfs(y+1,t);
//一直调用到最后一行,从最后一行开始,
//考虑到每一种情况;
for(int i=1;i<=n;i++)
{
if(map[y][i]=='#'&&visited[i]==0)
{ //需要满足的条件
visited[i]=1;
//标记已经走过
dfs(y+1,t+1);
//继续下一步dfs
visited[i]=0;
//恢复初始状态
}
}
}
int main()
{
while(1)
{
sum=0;
scanf("%d%d",&n,&k);
if(n==-1&&k==-1)
break;
memset(map,0,sizeof(map));
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf(" %c",&map[i][j]);
dfs(1,0);
//初始化y为第一行,次数为0
printf("%d\n",sum);
}
return 0;
}
三.代码
//用dfs来计算最短路径
#include<stdio.h>
int r,c,num=10000;
char map[41][41];
int dx[]={1,-1,0,0};
int dy[]={0,0,1,-1};
void dfs(int x,int y,int k)
{
if(x==r&&y==c)
{
if(num>k)
{
num=k;
}
}
for(int i=0;i<4;i++)
{
int nx=x+dx[i];
int ny=y+dy[i];
if(nx>=1&&nx<=c&&ny>=1&&ny<=r&&map[ny][nx]=='.')
{
map[ny][nx]='#';
dfs(nx,ny,k+1);
map[ny][nx]='.';
}
}
}
int main()
{
scanf("%d%d",&r,&c);
for(int i=1;i<=r;i++)
{
for(int j=1;j<=c;j++)
{
scanf(" %c",&map[i][j]);
}
}
map[1][1]='#';
dfs(1,1,1);
printf("%d",num);
}
//dfs遍历是否能够从(ha,la)到(hb,lb)
#include<stdio.h>
#include<string.h>
int dx[]={1,-1,0,0};
int dy[]={0,0,1,-1};
int n,ha,la,hb,lb,nx,ny;
bool flag;
char map[200][200];
void dfs(int x,int y)
{
for(int i=0;i<4;i++)
{
nx=x+dx[i];
ny=y+dy[i];
if(nx>=0&&nx<n&&ny>=0&&ny<n&&map[nx][ny]=='.')
{
map[nx][ny]='#';
if(nx==hb&&ny==lb)
{
printf("YES\n");
flag=true;
break;
}
else
dfs(nx,ny);
}
}
}
int main()
{
int k;
scanf("%d",&k);
for(int i=0;i<k;i++)
{
flag=false;
scanf("%d",&n);
memset(map,'#',sizeof(map));
for(int j=0;j<n;j++)
for(int h=0;h<n;h++)
{
scanf(" %c",&map[j][h]);
}
scanf("%d%d%d%d",&ha,&la,&hb,&lb);
if(map[ha][la]=='#'||map[hb][lb]=='#')
{
printf("NO\n");
continue;
}
else
{
map[ha][la]='#';
//标记起点走过
dfs(ha,la);
}
if(!flag)
printf("NO\n");
}
return 0;
}
//棋盘问题代码
#include<stdio.h>
#include<string.h>
int n,k;
char map[10][10];
int sum;
int visited[10];
void dfs(int y,int t)
{
if(t==k)
{
sum++;
return ;
}
if(y<=n)
dfs(y+1,t);
for(int i=1;i<=n;i++)
{
if(map[y][i]=='#'&&visited[i]==0)
{
visited[i]=1;
dfs(y+1,t+1);
visited[i]=0;
}
}
}
int main()
{
while(1)
{
sum=0;
scanf("%d%d",&n,&k);
if(n==-1&&k==-1)
break;
memset(map,0,sizeof(map));
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf(" %c",&map[i][j]);
dfs(1,0);
printf("%d\n",sum);
}
return 0;
}