dfs问题总结
dfs(Depth_First_Search):
它是一种图的遍历形式,其具体意义是从图中的某个顶点v出发,不停的遍历v的各个临界点,然后从各个临界点开始继续的向四周发散,直至遍历完所有与v路径相通的点,究其本质其实是应用了一种递归的思想;
模板代码为:
void dfs()//参数用来表示状态 { if(到达终点状态) { ...//根据题意添加 return; } if(越界或者是不合法状态) return; if(特殊状态)//剪枝 return ; for(扩展方式) { if(扩展方式所达到状态合法) { 修改操作;//根据题意来添加 标记; dfs(); (还原标记); //是否还原标记根据题意 //如果加上(还原标记)就是 回溯法 } } }
对于dfs来说简单的应用有全排列,迷宫问题,或者结合剪枝,回溯,dp等算法;下面我们来介绍其具体应用;
1.dfs全排列问题:
#include<iostream> #include<string.h> using namespace std; int a[101],b[101]; int i,j,n; void print() { for(i=1;i<=n;i++) { cout<<a[i]<<" "; } cout<<endl; } void dfs(int i) { if(i==n+1) { print(); return ; } for(int j=1;j<=n;j++)//int j是每一次都赋值,而j,则在递归过程中也会继续++; { if(b[j]==0) { a[i]=j; b[j]=1; dfs(i+1); b[j]=0; } } } int main() { cin>>n; memset(a,sizeof(a),0); memset(b,sizeof(b),0); dfs(1); return 0; }
全排列问题就是一种典型的dfs问题,由于需要遍历所有的数字,而且不能重复,因而与dfs的不断发散的主题刚好契合,当然对于c++来说next_permutation是更简单的一种全排列,同时这种全排列的解决方法还可以与回溯法相结合解决典型的
n皇后问题:
n皇后的问题关键是所有的位置既不能同行,也不能同列,还不可以同对角线,比如第一行的第一列放棋子,下一行就只能在二至n列放置棋子同时需要减去对角线上的情况,即为n*(n-1)*(n-2)...*1再减去对角线上的情况,其实只是上题的代码加上一个判断条件:if(abs(pre[x]-x)==abs(pre[y]-y))return false;
void generate(int index) { if(index==n+1) { res++; return; } for(int x=1;x<=n;x++) { if(hashTable[x]==true)//此行没下子; { bool flag=true; for(int pre=1;pre<index;pre++) { if(abs(P[pre]-x)==abs(pre-index)) { flag=false; break; } } if(flag) { P[index]=x; hashTable[x]=true; generate(index+1);//继续下一列; hashTable[x]=false;//此次排列结束,回溯; } } } }
3.迷宫类问题:对于迷宫类问题来说,若是求所有的可行路径就采用dfs,而求最短路径则bfs更加简便;
解决迷宫问题实际就是图的遍历思想,一步一步的发散寻路,到达一次终点res++,最终可以得到所有的路径。
题目:
从s到t,.意味着可以走,*意味着不能走,如果能走,输出路径,如果不能走,输出no。
输入:
5 6 ....S* .***.. .*..*. *.***. .T....
输出:
....m* .***mm .*..*m *.***m .Tmmmm
解决代码:
#include <iostream> #include <string> using namespace std; int n, m; string maze[110]; bool vis[110][110]; bool in(int x,int y){//防止走到地图外面 return 0<=x&&x<n&&0<=y&&y<m; } bool dfs(int x,int y){//x代表行,y代表列 if(maze[x][y]=='T'){ return true; } vis[x][y]=1;//标记当前点已走过 maze[x][y]='m';//走过的点用字符m标记 int tx = x-1,ty=y;//向上搜 if(in(tx,ty)&&maze[tx][ty]!='*'&&!vis[tx][ty]){ if(dfs(tx,ty)){ return true; } } tx=x,ty=y-1;//左 if(in(tx,ty)&&maze[tx][ty]!='*'&&!vis[tx][ty]){ if(dfs(tx,ty)){ return true; } } tx=x+1,ty=y;//下 if(in(tx,ty)&&maze[tx][ty]!='*'&&!vis[tx][ty]){ if(dfs(tx,ty)){ return true; } } tx=x,ty=y+1;//右 if(in(tx,ty)&&maze[tx][ty]!='*'&&!vis[tx][ty]){ if(dfs(tx,ty)){ return true; } } vis[x][y]=0; maze[x][y]='.'; 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; } } } if(dfs(x,y)){ for(int i=0;i<n;++i){ cout<<maze[i]<<endl; } } else{ cout<<"NO!"<<endl; } return 0; }
但一般迷宫问题并不会出现DFS,因为对于迷宫问题来说有太多的不必要的走法需要记录,例如在i+1步到迷宫边界,那么回溯一步,继续向别处走也是一种迷宫的走法,一般DFS在迷宫中主要用于在BFS算法进行求解最短路径时,输出最短路的路径;
void dfs(int x, int y) //递归打印 { if (x == 0 && y == 0)return; dfs(father[x][y].x, father[x][y].y); //cout<<father[x][y].dir; cout<<father[x][y].dir<<father[x][y].x<<father[x][y].y<<endl;; }
另附第九届蓝桥杯
全球变暖:
标题:全球变暖
你有一张某海域NxN像素的照片,”.”表示海洋、”#”表示陆地,如下所示:
…….
.##….
.##….
….##.
..####.
…###.
…….
其中”上下左右”四个方向上连在一起的一片陆地组成一座岛屿。例如上图就有2座岛屿。
由于全球变暖导致了海面上升,科学家预测未来几十年,岛屿边缘一个像素的范围会被海水淹没。具体来说如果一块陆地像素与海洋相邻(上下左右四个相邻像素中有海洋),它就会被淹没。
例如上图中的海域未来会变成如下样子:
…….
…….
…….
…….
….#..
…….
…….
请你计算:依照科学家的预测,照片中有多少岛屿会被完全淹没。
【输入格式】
第一行包含一个整数N。 (1 <= N <= 1000)
以下N行N列代表一张海域照片。
照片保证第1行、第1列、第N行、第N列的像素都是海洋。
【输出格式】
一个整数表示答案。
【输入样例】
7
…….
.##….
.##….
….##.
..####.
…###.
…….
【输出样例】
1
资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms
AC代码:
#include<iostream> #define INF 10000 using namespace std; int maxn=10010; int N; int count1=0; int res; char pool[10010][10010]; int n_x,n_y; int row[4]={0,0,-1,1}; int col[4]={1,-1,0,0}; void dfs(int x,int y) { pool[x][y]='.'; for(int i=0;i<4;i++) { n_x=x+row[i]; n_y=y+col[i]; if(n_x>=0&&n_x<N&&n_y>=0&&n_y<N&&pool[n_x][n_y]=='#') { dfs(n_x,n_y); } } return ; } int main() { cin>>N; int res=0; for(int i=0;i<N;i++) { for(int j=0;j<N;j++) { cin>>pool[i][j]; } } for(int i=0;i<N;i++) { for(int j=0;j<N;j++) { if(pool[i][j]=='#') { bool flag=0; for(int k=0;k<4;k++) { int t1,t2; t1=i+row[k]; t2=j+col[k]; if(t1<0||t1>=N||t2<0||t2>=N) { continue; } else { if(pool[t1][t2]=='.') { flag=1; } } } if(!flag) { count1++; } } } } for(int i=0;i<N;i++) { for(int j=0;j<N;j++) { if(pool[i][j]=='#'){ dfs(i,j); res++; } } } printf("%d %d\n",res,count1); }

浙公网安备 33010602011771号