目录
深度优先搜索:
深度优先搜索属于图算法的一种,英文缩写为DFS即Depth First Search.其过程简要来说是对每一个可能的分支路径深入到不能再深入为止,而且每个节点只能访问一次。
深度优先遍历图的方法是,从图中某顶点v出发:
(1)访问顶点v;
(2)依次从v的未被访问的邻接点出发,对图进行深度优先遍历;直至图中和v有路径相通的顶点都被访问;
(3)若此时图中尚有顶点未被访问,则从一个未被访问的顶点出发,重新进行深度优先遍历,直到图中所有顶点均被访问过为止。
框架展示:
例一、中国象棋
题目描述:
代码如下:
#include<cstdio>
char map[10][10];
bool f;
int visited[10][10]; //字符串长度为9,至少要开10的长度,因为有'\0'
int dir[8][2]={{-2,-1},{-2,1},{-1,2},{1,2},{2,1},{2,-1},{1,-2},{-1,-2}};
bool in(int x,int y){ //判断是否在棋盘内
if(x>=0&&x<10&&y>=0&&y<9)
return true;
return false;
}
void dfs(int x,int y){
visited[x][y]=1; //标记已访问
if(f){ //已跳到马需要跳到的位置
return;
}
if(map[x][y]=='T'){ //找到马需要跳到的位置
f=true;
return;
}
for(int i=0;i<8;++i){
int tx=x+dir[i][0];
int ty=y+dir[i][1];
if(in(tx,ty)&&map[x][y]!='#'&&!visited[tx][ty])
dfs(tx,ty);
}
}
int main(){
int x,y;
for(int i=0;i<10;++i)
scanf("%s",map[i]);
for(int i=0;i<10;++i){
for(int j=0;j<9;++j){
if(map[i][j]=='S'){
x=i;
y=j;
break;
}
}
}
dfs(x,y);
if(f)
printf("Yes\n");
else
printf("No\n");
return 0;
}
运行结果:
例二、迷宫
题目描述:
输入:
第一行为行列数n和m
其余n行输入n*m的地图
输出:
迷宫起点到终点最短路径
代码如下:
#include<iostream>
#include<string>
using namespace std;
int n,m;
int ans=10000000;
string maze[110];
bool visited[110][110];
int dire[4][2]={{0,-1},{-1,0},{0,1},{1,0}};
bool in(int x,int y){
if(x>=0&&x<n&&y>=0&&y<m)
return true;
return false;
}
bool dfs(int x,int y,int step){
if(maze[x][y]=='T'){
if(step<ans){
ans=step;
}
return true;
}
visited[x][y]=1;
for(int i=0;i<4;++i){
int tx=x+dire[i][0];
int ty=y+dire[i][1];
if(in(tx,ty)&&maze[tx][ty]!='*'&&!visited[tx][ty]){
dfs(tx,ty,step+1);
}
}
visited[x][y]=0;
return false;
}
int main(){
cin>>n>>m;
for(int i=0;i<n;++i)
cin>>maze[i];
int x,y;
for(int i=0;i<n;++i){
for(int j=0;j<m;++j){
if(maze[i][j]=='S'){
x=i;
y=j;
}
}
}
dfs(x,y,0);
cout<<ans<<endl;
return 0;;
}
运行结果:
例三、迷宫解的方案数
题目描述:
输出:
从起点到达终点的路径的条数
代码如下:
#include<cstdio>
int n,m,x,y,ans;
char map[15][15];
bool visited[15][15];
void dfs(int x,int y){
if(x<0||x>=n||y<0||y>=m||visited[x][y]||map[x][y]=='#')
return;
if(map[x][y]=='e'){
++ans;
return;
}
visited[x][y]=1;
dfs(x-1,y);
dfs(x+1,y);
dfs(x,y-1);
dfs(x,y+1);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=0;i<n;++i)
scanf("%s",map[i]);
for(int i=0;i<n;++i){
for(int j=0;j<m;++j){
if(map[i][j]=='s'){
x=i;
y=j;
}
}
}
dfs(x,y);
printf("%d\n",ans);
return 0;
}
运行结果:
例四、最大的蛋糕块
题目描述:
输入:
第一行为蛋糕的行列数n,m
其余n行为蛋糕
输出:
蒜头君最大可以吃到的蛋糕占据的网格数
代码如下:
#include<cstdio>
int n,m,cnt,ans;
char map[1005][1005];
bool visited[1005][1005];
void dfs(int x,int y){
if(x<0||x>=n||y<0||y>=m||visited[x][y]||map[x][y]=='.')
return;
visited[x][y]=1;
++cnt;
dfs(x-1,y);
dfs(x+1,y);
dfs(x,y-1);
dfs(x,y+1);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=0;i<n;++i)
scanf("%s",map[i]);
for(int i=0;i<n;++i){
for(int j=0;j<m;++j){
if(!visited[i][j]&&map[i][j]=='#'){
cnt=0;
dfs(i,j);
if(cnt>ans)
ans=cnt;
}
}
}
printf("%d\n",ans);
}
运行结果:
例五、家谱
题目描述:
输出:
输出n行,每行有一个整数,表示第i个人有多少个直系后代
代码如下:
#include<cstdio>
#include<vector>
using namespace std;
vector<int> son[100005];
int ans[100005];
bool f[100005];
int dfs(int u){
int ret=0;
for(int i=0;i<son[u].size();++i)
ret+=dfs(son[u][i]);
ans[u]=ret;
return ret+1;
}
int main(){
int n,x,y,u;
scanf("%d",&n);
for(int i=0;i<n-1;++i){
scanf("%d%d",&x,&y);
son[x].push_back(y);
f[y]=1;
}
for(int i=1;i<=n;++i){
if(!f[i]){
u=i;
break;
}
}
dfs(u);
for(int i=1;i<=n;++i)
printf("%d\n",ans[i]);
return 0;
}
运行结果:
另附(vector讲解):
例六、马的覆盖点
题目描述:
输入:
第一行输入两个整数 n (1 ≤ x ≤ 100), m(1≤ m ≤ 100) 代表棋盘行和列的大小。
第二行输入两个整数 x (1 ≤ x ≤ n), y (1 ≤ y ≤ m) 代表马开始所的位置。
输出:
输出整个棋盘,'.'代表棋盘上可以落子的点。'#'这个代表马三步能到达的点。
代码如下:
#include<cstdio>
char s[105][105];
int n,m;
int dir[8][2]={{-2,-1},{-2,1},{2,-1},{2,1},{1,2},{1,-2},{-1,2},{-1,-2}};
void dfs(int x,int y,int step){
if(step>3)
return;
if(x<0||x>=n||y<0||y>=m)
return;
s[x][y]='#';
for(int i=0;i<8;++i)
dfs(x+dir[i][0],y+dir[i][1],step+1);
}
int main(){
int x,y;
scanf("%d%d%d%d",&n,&m,&x,&y);
for(int i=0;i<n;++i){
for(int j=0;j<m;++j){
s[i][j]='.';
}
}
dfs(x-1,y-1,0);
for(int i=0;i<n;++i)
printf("%s\n",s[i]);
return 0;
}
运行结果:
例七、王子救公主
题目描述:
代码如下:
#include<cstdio>
int n,m;
char map[105][105];
bool visited[105][105][2];
void dfs(int x,int y,int d){
if(x<0||x>=n||y<0||y>=m||visited[x][y][d]||map[x][y]=='#')
return;
visited[x][y][d]=1;
dfs(x-(2-d),y,d);
dfs(x+(2-d),y,d);
dfs(x,y-(2-d),d);
dfs(x,y+(2-d),d);
}
int main(){
int x,y;
bool ans;
scanf("%d%d",&n,&m);
for(int i=0;i<n;++i){
scanf("%s",map[i]);
}
for(int i=0;i<n;++i){
for(int j=0;j<m;++j){
if(map[i][j]=='w'){
x=i;
y=j;
break;
}
}
}
dfs(x,y,0); //0为王子走2步,1为公主走1步
ans=0;
for(int i=0;i<n;++i){
for(int j=0;j<m;++j){
if(map[i][j]=='g'){
x=i;
y=j;
break;
}
}
}
dfs(x,y,1);
for(int i=0;i<n;++i){
for(int j=0;j<m;++j){
if(visited[i][j][0]&&visited[i][j][1]){
ans=true;
}
}
}
if(ans)
printf("yes\n");
else
printf("no\n;");
return 0;
}
运行结果:
例八、开公司
题目描述:
代码如下:
#include<cstdio>
int task[15][15];
bool visited[15];
int n,ans;
void dfs(int x,int t){
if(x==n){
if(t<ans)
ans=t;
return;
}
for(int i=0;i<n;++i){
if(!visited[i]){
visited[i]=1;
dfs(x+1,t+task[x][i]);
visited[i]=0;
}
}
}
int main(){
scanf("%d",&n);
for(int i=0;i<n;++i){
for(int j=0;j<n;++j)
scanf("%d",&task[i][j]);
}
ans=20000;
dfs(0,0);
printf("%d\n",ans);
return 0;
}