• 深度搜索(dfs)+典型例题(八皇后)


    深度优先搜索简称深搜,从起点出发,走过的点要做标记,发现有没走过的点,就随意挑一个往前走,走不了就回退,此种路径搜索策略就称为“深度优先搜索”,简称“深搜”。

    如上面的图所示:加入我们要找一个从V0到V6的一条最短的路径。我们可以看到有许多的路我们可以走。

    V0——V3——V5——V6;

    V0——V3——V1——V4;

    V0——V3——V1——V2——V6;

    V0——V1——V4;

    V0——V1——V3——V5——V6;

    V0——V1——V2——V6;

    V0——V2——V6;

    前两组,是从节点V3开始分的,然后遍历了后面的所有路径,然后找到了我们需要的解。

    从第三条路径我们就可以看到,到了V4之后就没有路了,那么我们就需要返回到V1找下一条路径。

    V1节点所有的路径我们就都找完了,就开始找V2节点的路径了。由于我们一开始不知道哪一条路可以走到V6和不知道哪一条路径最短,所以我们需要找出所有的路,然后再来判断哪一条路最短。

    上面我们找到了所有的路径,然后判断最小的路径是V0——V2——V6,这就是最优解。

    深搜的基本模板:

    int search(int t)
    {
        if(满足输出条件)
        {
            输出解;
        }
        else
        {
            for(int i=1;i<=尝试方法数;i++)
                if(满足进一步搜索条件)
                {
                    为进一步搜索所需要的状态打上标记;
                    search(t+1);
                    恢复到打标记前的状态;//回溯
                }
        }
    }

    总结:深搜就是要找到所有可能的解,然后再来找到最优解,需要我们遍历所有的路径。

    典型例题(八皇后):链接:https://www.luogu.org/problem/P1219

    题目描述

    检查一个如下的6 x 6的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行、每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子。

    上面的布局可以用序列2 4 6 1 3 5来描述,第i个数字表示在第i行的相应位置有一个棋子,如下:

    行号 1 2 3 4 5 6

    列号 2 4 6 1 3 5

    这只是跳棋放置的一个解。请编一个程序找出所有跳棋放置的解。并把它们以上面的序列方法输出。解按字典顺序排列。请输出前3个解。最后一行是解的总个数。

    输入格式

    一个数字N (6 <= N <= 13) 表示棋盘是N x N大小的。

    输出格式

    前三行为前三个解,每个解的两个数字之间用一个空格隔开。第四行只有一个数字,表示解的总数。

    输入输出样例

    输入 #1
    6
    
    输出 #1
    2 4 6 1 3 5
    3 6 2 5 1 4
    4 1 5 2 6 3
    4

    对于该题目,因为我们不知道怎样来放这个点,所以我们需要将所有的点都试一下,防止漏掉哪一个点:

    题解:

    #include<iostream>
    using namespace std;
    int sum=1;
    int A[200]={0},B[200]={0},C[200]={0},D[200]={0};//表示横行,B表示纵行,C表示左下到右上的对角线,D表示左上到右下的对角线 
    int n;
    int print()//输出前三个 
    {
        
        if(sum<=3)
        {
            for(int i=1;i<=n;i++)
             cout<<A[i]<<" ";     
             cout<<endl;
        }
        sum++;
     }
     void dfs(int i)
     {
          if(i>n)
          {
              print();
              return ;
           } 
         if(i<=n)
         {
             for(int j=1;j<=n;j++)
             {
                 if(B[j]!=1&&C[j-i+n]!=1&&D[i+j]!=1)
                 {
                     A[i]=j;//记录纵列的值 
                     B[j]=1;//标记纵列 
                     C[j-i+n]=1;//标记对角线 
                     D[i+j]=1;//标记对角线 
                     dfs(i+1);//接着搜下一个点 
                     B[j]=0;//清除记忆 
                     C[j-i+n]=0;
                     D[j+i]=0;
                 }
             }
         }
     }
     int main()
     {
         cin>>n;
         dfs(1);
         cout<<sum-1;
         return 0;
     }
      
  • 相关阅读:
    ubuntu 更新软件
    如何在linux(lubuntu)下搭建C/C++开发环境
    Linux下如何查看版本信息
    知识点笔记
    Require.js中使用jQuery 插件
    async中常用总结
    node.js在遇到“循环+异步”时的注意事项
    前端性能优化
    生产/消费者问题
    线程与内存
  • 原文地址:https://www.cnblogs.com/zhoubo123/p/11373472.html
Copyright © 2020-2023  润新知