zoukankan      html  css  js  c++  java
  • 深度搜索(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;
     }
      
  • 相关阅读:
    Call KernelIoControl in user space in WINCE6.0
    HOW TO:手工删除OCS在AD中的池和其他属性
    关于新版Windows Server 2003 Administration Tools Pack
    关于SQL2008更新一则
    微软发布3款SQL INJECTION攻击检测工具
    HyperV RTM!
    OCS 2007 聊天记录查看工具 OCSMessage
    CoreConfigurator 图形化的 Server Core 配置管理工具
    OC 2007 ADM 管理模板和Live Meeting 2007 ADM 管理模板发布
    Office Communications Server 2007 R2 即将发布
  • 原文地址:https://www.cnblogs.com/zhoubo123/p/11373472.html
Copyright © 2011-2022 走看看