Live2d Test Env

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);
}

 

posted @ 2019-11-09 17:38  lszz  阅读(891)  评论(0)    收藏  举报