一、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;
}