DFS,BFS题解

一、dfs

深度优先搜索(dfs),是从图中的一个顶点出发,每次遍历当前访问顶点的临界点,一直到访问的顶点没有未被访问过的临界点为止。然后采用依次回退的方式,查看来的路上每一个顶点是否有其它未被访问的临界点。访问完成后,判断图中的顶点是否已经全部遍历完成,如果没有,以未访问的顶点为起始点,重复上述过程。

例1

#include<iostream>

using namespace std;

int n,a[9],b[9];

void print(){

for(int i=1;i<=n;i++){//输出当前排列

cout<<" "<<a[i];

}cout<<endl;

}

void dfs(int x){

if(x==n+1){//当x=n+1时说明a[i]已经放入了n个元素

print();

return ;

}

for(int i=1;i<=n;i++){

if(b[i]==0){

a[x]=i;

b[i]=1;//做标记,用于判断a[i]是否放入元素

dfs(x+1);

b[i]=0;//取消标记

}

}

}

int main(){

cin>>n;

dfs(1);

return 0;

}

例2

洛谷 P2404 自然数的拆分问题

#include<iostream>

using namespace std;

int n,m,a[10];

void print(int x){

for(int i=1;i<=x;i++){

if(i==x)cout<<a[i];

else cout<<a[i]<<"+";

}cout<<endl;

}

void dfs(int x){

if(m==0){//m=0,说明自然数n已经拆分完成

print(x-1);

return ;

}

for(int i=1;i<n;i++){

if(m-i>=0&&i>=a[x-1]){//m-i>=0保证不拆过头,i>=a[x-1]确保大的数放在数组后位

a[x]=i;

m-=i;减去已拆分部分

dfs(x+1);

m+=i;回复已拆分部分

}else{

continue;

}

}

}

int main(){

cin>>n;

m=n;

dfs(1);

return 0;

}

二、bfs

广度优先搜索类似于树的层次遍历。从图中的某一顶点出发,遍历每一个顶点时,依次遍历其所有的邻接点,然后再从这些邻接点出发,同样依次访问它们的邻接点。按照此过程,直到图中所有被访问过的顶点的邻接点都被访问到。

最后还需要做的操作就是查看图中是否存在尚未被访问的顶点,若有,则以该顶点为起始点,重复上述遍历的过程

例1

#include<iostream>

#include<cstdio>

#include<queue>

#include<cstring>

using namespace std;

#define maxn 310

struct coord{//一个结构体存储x,y两个坐标

int x,y;

};

queue<coord> Q;

int ans[maxn][maxn];

int walk[8][2]={{2,1},{1,2},{-1,2},{-2,1},{-2,-1},{-1,-2},{1,-2},{2,-1}};//记录马能走的8个方向

int main(){

int n,m,sx,sy;

memset(ans,-1,sizeof(ans));

cin>>n>>m>>sx>>sy;

coord tmp={sx,sy};

Q.push(tmp);//使起点入队

ans[sx][sy]=0;

while(!Q.empty()){

coord u=Q.front();//取出队首

int ux=u.x,uy=u.y;

Q.pop();

for(int k=0;k<8;k++){

int x=ux+walk[k][0],y=uy+walk[k][1];

int d=ans[ux][uy];

if(x<1||x>n||y<1||y>m||ans[x][y]!=-1)

continue;

ans[x][y]=d+1;

coord tmp={x,y};

Q.push(tmp);

}

} for(int i=1;i<=n;i++,puts(""))

for(int j=1;j<=m;j++)

printf("%-5d",ans[i][j]);

return 0;

}

例2

#include<iostream>

#include<queue>

using namespace std;

struct node{

int floor ,d;//队列中记录的层数和按钮次数

};

queue<node> Q;

int n,a,b;

int k[1000],vis[1000];

int main(){

cin>>n>>a>>b;

for (int i = 1; i <= n; i++){

cin >> k[i];

}

Q.push((node){a,0});//将初始元素加入队列

vis[a]=1;//记录初始楼层已访问过

node now;

while ( !Q.empty()) {

now = Q.front();

Q.pop();

if (now.floor == b) break;

for (int sign = -1; sign <= 1; sign += 2){//sign枚举-1和1

int dist = now.floor + k[now.floor] * sign;

if (dist >= 1 && dist <= n && vis[dist]==0){//如果按按钮能到达的楼层有效并且未访问该楼层

Q.push((node){dist, now.d+1});

vis[dist] = 1;

}

}

}

if (now.floor == b){

cout << now.d <<endl;

}else{

cout << -1 << endl;

}return 0;

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值