算法-DFS搜索


DFS:一种用于遍历或搜索树或图的算法。 沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当节点v的所在边都己被探寻过或者在搜寻时结点不满足条件,搜索将回溯到发现节点v的那条边的起始节点。整个进程反复进行直到所有节点都被访问为止。属于盲目搜索,最糟糕的情况算法时间复杂度为O(!n)。
优先考虑深度 一条路径结束后再考虑下一条

一般搜索(栈)与递归搜索的区别

1- 2
| /
3 — 4
一般搜索:先找到每个出边所对应的未被处理的点(2,3同时被1发现并入栈),在进行依次进行深度搜索即1 24 3或1 3 24但不可能是1234
递归搜索:依次找到每个出边所对应的未被处理的点(2,3先后被发现),故:可能1先发现2,2发现3,4, 可能是12 3 4

基本操作

DFS(v) // v 可以是图中的一个顶点,也可以是抽象的概念,如 dp 状态等。
在 v 上打访问标记
for u in v 的相邻节点
… if u 没有打过访问标记 then
… … DFS(u)
… … … end
… … end
… end

全排列问题

题意:给一个数字n,输出1~n的全排列

#include<iostream>
using namespace std;
int a[100];//记录顺序
int vis[100];//标记访问
int n;
void dfs(int x){
	if(x>n){//搜索结束,输出
		for(int i=1;i<=n;i++){
			printf("%d",a[i]);
		}
		printf("\n");
	}
	else{
		for(int i=1;i<=n;i++){
			if(vis[i]==0){//若没有访问过,则访问
				a[x]=i;//记录数字
				vis[i]=1;//标记已访问
				dfs(x+1);//递归搜索
				vis[i]=0;//回溯
			}
		}
	}
	return;//返回上一级
}
int main(){
	while(~scanf("%d",&n)){
		dfs(1);
	}
	return 0;
}

迷宫(POJ 3984简化版)

题意

0为可走的路 1为墙,找到从左上角到右下角的路(找到即可,不需最短)
0 1 0 1 0
0 1 0 1 1
0 0 0 0 1
0 1 1 0 1
0 1 0 0 0

代码1(找到即可,不需最短)

int a[100][100];//迷宫
int vis[100][100];//访问
int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};
bool flag=false;
int n;//规格n*n
void dfs(int x,int y){
	if(flag==true){//如果已经找到就不需要再找了
		return;
	}
	if(x==n&&y==n){//如果到达目的地,能够找到这样的路,flag为true,停止递归
		flag=true;
		return;
	}
	vis[x][y]=1;
	for(int i=0;i<4;i++){//向四周找是否有路可走
		int nxt_x=x+dx[i];
		int nxt_y=y+dy[i];
		if(nxt_x<1||nxt_y<1||nxt_x>n||nxt_y>n){//超过n*n边界,不进行递归
			continue;
		}
		if(a[nxt_x][nxt_y]==0&&vis[nxt_x][nxt_y]==0){//当该点为0且未曾经过时,递归
			dfs(nxt_x,nxt_y);
		}
	}
}

代码2(最小步数)

#include<iostream>
using namespace std;
int a[100][100];//迷宫
int vis[100][100];//访问
int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};
int n;//规格n*n
int stepmin=100000;//设置步数最小值
void dfs(int x,int y,int step){
	if(x==n&&y==n){//如果到达目的地,更新步数最小值
        if(step<stepmin){
			stepmin=step;
		}
		return;
	}
	for(int i=0;i<4;i++){//向四周找是否有路可走
		int nxt_x=x+dx[i];
		int nxt_y=y+dy[i];
		if(nxt_x<1||nxt_y<1||nxt_x>n||nxt_y>n){//超过n*n边界,不进行递归
			continue;
		}
		if(a[nxt_x][nxt_y]==0&&vis[nxt_x][nxt_y]==0){//当该点为0且未曾经过时,递归
			vis[nxt_x][nxt_y]=1;
			dfs(nxt_x,nxt_y,step+1);
			vis[nxt_x][nxt_y]=0;
		}
	}
	return;
}

int main(){
	while(~scanf("%d",&n)){
		int startx,starty;
		scanf("%d%d",&startx,&starty);
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				scanf("%d",&a[i][j]);
			}
		}
		vis[startx][starty]=1;
		dfs(startx,starty,0);
		printf("%d\n",stepmin);
	}
	return 0;
}

代码3(写出所有路径)

洛谷例题

#include<bits/stdc++.h>
using namespace std;
int mp[100][100];
int m,n;
int startx,starty,endx,endy;
int vis[100][100];
bool flag;
int dx[4]={0,-1,0,1};
int dy[4]={-1,0,1,0};
struct node{
	int x,y;
};
vector<node> v;
void dfs(int x,int y){
	if(x==endx&&y==endy){
		for(int i=0;i<(int)v.size();i++){
			cout<<"("<<v[i].x<<","<<v[i].y<<")->";
		}
		cout<<"("<<endx<<","<<endy<<")"<<endl;
		flag=true;
		return;
	}
	vis[x][y]=1;
	v.push_back({x,y});
	for(int i=0;i<4;i++){
		int nxt_x=x+dx[i];
		int nxt_y=y+dy[i];
		if(nxt_x<1||nxt_y<1||nxt_x>m||nxt_y>n){
			continue;
		}
		if(!vis[nxt_x][nxt_y]&&mp[nxt_x][nxt_y]==1){
			dfs(nxt_x,nxt_y);
		}
	}
	vis[x][y]=0;
	v.pop_back();
}
int main(){
	scanf("%d%d",&m,&n);
	for(int i=1;i<=m;i++){
		for(int j=1;j<=n;j++){
			scanf("%d",&mp[i][j]);
		}
	}
	scanf("%d%d%d%d",&startx,&starty,&endx,&endy);
	dfs(startx,starty);
	if(!flag){
		cout<<"-1"<<endl;
	}
	return 0;
}

代码4(写出第一个最短路径)

#include<bits/stdc++.h>
using namespace std;
int mp[100][100];
int m,n,stepmin=100000;
int startx,starty,endx,endy;
int vis[100][100];
bool flag;
int dx[4]={0,-1,0,1};
int dy[4]={-1,0,1,0};
struct node{
	int x,y;
};
vector<node> pv;
vector<node> minv;
void dfs(int x,int y,int step){
	if(x==endx&&y==endy){
		if(step<stepmin){
			stepmin=step;
			minv.clear();
			for(int i=0;i<(int)pv.size();i++){
				minv.push_back({pv[i].x,pv[i].y});
			}
			flag=true;
			return;
		}
	}
	vis[x][y]=1;
	pv.push_back({x,y});
	for(int i=0;i<4;i++){
		int nxt_x=x+dx[i];
		int nxt_y=y+dy[i];
		if(nxt_x<1||nxt_y<1||nxt_x>m||nxt_y>n){
			continue;
		}
		if(!vis[nxt_x][nxt_y]&&mp[nxt_x][nxt_y]==1){
			dfs(nxt_x,nxt_y,step+1);
		}
	}
	vis[x][y]=0;
	pv.pop_back();
}
int main(){
	scanf("%d%d",&m,&n);
	flag=false;
	for(int i=1;i<=m;i++){
		for(int j=1;j<=n;j++){
			scanf("%d",&mp[i][j]);
		}
	}
	scanf("%d%d%d%d",&startx,&starty,&endx,&endy);
	dfs(startx,starty,0);
	if(!flag){
		cout<<"-1"<<endl;
	}
	else{
		for(int i=0;i<(int)minv.size();i++){
			cout<<"("<<minv[i].x<<","<<minv[i].y<<")->";
		}
		cout<<"("<<endx<<","<<endy<<")"<<endl;
	}
	return 0;
}

八皇后

题目
代码

#include <iostream>
using namespace std;
int n,num;
int a[100],col[100],dg[100],udg[100];
void dfs(int row){
    if(row==n+1){
    	num++;
    	if(num<=3){
			for(int i=1;i<=n;i++){
				cout<<a[i]<<" ";
	        }
			cout<<"\n";
		}
        return;
    }
    for(int i=1;i<=n;i++)
        if(col[i]==0&&dg[row+i]==0&&udg[row-i+n]==0){
            a[row]=i;
            col[i]=dg[row+i]=udg[row-i+n]=1;
            dfs(row + 1);
            col[i]=dg[row+i]=udg[row-i+n]=0;
            a[row]=0;
        }
}
int main(){
    cin>>n;
    dfs(1);
    cout<<num;
    return 0;
}

参考

参考视频

参考博客

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值