深度优先遍历(dfs)是对一个连通图进行遍历的算法。它的思想是从一个顶点开始,沿着一条路一直走到底,若是发现不能到达目标解,那就返回到上一个节点,而后从另外一条路开始走到底,这种尽可能往深处走的概念便是深度优先的概念。c++
简而言之:不撞南墙不回头算法
模板以下:数组
void dfs(int t)//t表明目前dfs的深度 { if(知足输出条件||走不下去了) { 输出解; return; } else { for(int i=1;i<=尝试方法数;i++) if(知足进一步搜索条件) { 为进一步搜索所须要的状态打上标记; dfs(t+1); 恢复到打标记前的状态;//也就是说的{回溯一步} } } }
#include<bits/stdc++.h> using namespace std; int a[14],b[14],c[29],d[29];//分别存横、列、左对角线、右对角线访问标记 int n; int cnt=0; void print() { cnt++; if(cnt<=3) { for(int i=1;i<=n;i++) cout<<a[i]<<" "; cout<<endl; } } void dfs(int k) { int i=k; for(int j=1;j<=n;j++) { if(b[j]==0&&c[i+j]==0&&d[i-j+n]==0)//知足未被访问 { a[i]=j; b[j]=1;c[i+j]=1;d[i-j+n]=1;//分别在竖排,左对角线,右对角线打上标记 if(k<n) dfs(k+1); //放置下一横排的皇后 else if(k==n) print(); b[j]=0;c[i+j]=0;d[i-j+n]=0;//回溯,标记从新置为0 } } } int main() { cin>>n; dfs(1); cout<<cnt; return 0; }
#include<bits/stdc++.h> using namespace std; long long a[52][52]; int n; set<int> s; //set集合中数据惟一且有序 void dfs(int x,int y,int sum){ if(x==n && y==n){ s.insert(sum); //走到(n,n)则把sum插入集合s return; } if(x+1<=n){ dfs(x+1,y,sum+a[x+1][y]);//向下走 } if(y+1<=n){ dfs(x,y+1,sum+a[x][y+1]);//向右走 } } int main() { cin>>n; for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ cin>>a[i][j]; //录入矩阵 } } dfs(1,1,a[1][1]); //开始深搜 cout<<s.size()<<endl;//输出集合s的大小 return 0; }
广度优先搜索较之深度优先搜索之不一样在于,深度优先搜索旨在无论有多少条岔路,先一条路走到底,不成功就返回上一个路口而后就选择下一条岔路,而广度优先搜索旨在面临一个路口时,把全部的岔路口都记下来,而后选择其中一个进入,而后将它的分路状况记录下来,而后再返回来进入另一个岔路,并重复这样的操做。spa
简而言之:地毯式搜索或者说像水波纹同样四散开来code
模板以下:队列
//一般用队列queue实现,或者有些时候用数组模拟队列 void bfs() { 初始化队列q q.push(起点); 标记上起点; while(!q.empty()) { 取队首元素u; q.pop();//队首元素出队 for(int i=0;i<能够走的方向数;i++) { if(下一步知足边界内,未访问等条件) { q.push();//该点入队 标记上该点; ... } } } }
此题要求马从某点到达某点的最少要走几步,优先用bfsci
#include<bits/stdc++.h> using namespace std; int h[8]={-2,-1,1,2,-2,-1,1,2},z[8]={1,2,2,1,-1,-2,-2,-1};//8个方向 int vis[410][410]; int cnt[410][410];//记录到达每一个坐标点的步数 queue<pair<int,int> >q; int n,m; void bfs() { while(!q.empty()) { int x=q.front().first; int y=q.front().second; q.pop(); for(int i=0;i<8;i++) { int xx=x+h[i]; int yy=y+z[i]; if(xx>n||xx<1||yy>m||yy<1||vis[xx][yy]==1)continue;//到达边界或已经访问则跳过这次循环 q.push(make_pair(xx,yy)); vis[xx][yy]=1; cnt[xx][yy]=cnt[x][y]+1; } } } int main() { memset(cnt,-1,sizeof(cnt)); int x,y; cin>>n>>m>>x>>y; vis[x][y]=1; cnt[x][y]=0; q.push(make_pair(x,y)); bfs(); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { printf("%-5d",cnt[i][j]);//控制格式 } cout<<endl; } return 0; }
此题的关键是经过广搜把 1 外围的 0 打上标记get
#include<bits/stdc++.h> using namespace std; int h[4]={-1,0,1,0},z[4]={0,-1,0,1}; int n,a[35][35]; queue<pair<int,int> >q; int main() { cin>>n; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) cin>>a[i][j]; for(int i=0;i<=n+1;i++)//在四周加0,避免在角落的0搜不过去 { a[0][i]=0; a[n+1][i]=0; a[i][0]=0; a[n+1][i]=0; } q.push(make_pair(0,0)); while(!q.empty()) { int x=q.front().first; int y=q.front().second; q.pop(); for(int i=0;i<4;i++) { int x2=x+h[i]; int y2=y+z[i]; if(x2>=0&&y2>=0&&x2<=n+1&&y2<=n+1&&a[x2][y2]==0) { a[x2][y2]=-1;//1外围的0标志为-1 q.push(make_pair(x2,y2)); } } } for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { if(a[i][j]==-1)cout<<"0 "; else if(a[i][j]==1)cout<<"1 "; else if(a[i][j]==0)cout<<"2 "; } cout<<endl; } return 0; }
综上,其实不少题dfs和bfs均可以解,可是在最短(优)路径问题上最好用广度优先bfsit