步步为营(十五)搜索(一)DFS 深度优先搜索
前方大坑预警!
先讲讲什么是搜索吧。
有一天你去一个果园摘梨子,果农告诉你。有一棵树上有一个金子做的梨子,找到就是你的,你该怎么找? 
地图例如以下: 
S 0 0 0 0 
0 0 0 0 0 
0 0 0 0 0 
0 0 0 0 0 
0 0 0 0 G
废话。挨个找呗~ 这就叫做搜索。
在一个区间内找到符合条件的值的过程,就是搜索。(?)
最简单的就是穷举,挨个找。
由于都能够走,所以从(1,1)到(n。n)一路走过去,能找到即可。
可是果农告诉你,这个果园有的位置是肥料坑~你不能过去(当然。你非要去坑里游两圈也不拦着你),那么这个果园的地图就成了这个样子。
S 0 1 1 0 
0 1 0 0 0 
0 0 1 1 0 
0 1 0 0 0 
0 0 0 0 G
这个时候,果园又来了好几个摘梨子的。果农就说:“金梨子仅仅有一个,你们谁最先找到就归谁!
”
那么怎样去寻找到一条最短的路程呢?
这时候就该用一些策略了,于是,DFS(深搜)登场了。
首先。为什么叫深度优先搜索?
深度,在这样的环境下,能够看做离起始位置的步数。
更学术点的说法。能够看做“单位距离下。离起始状态的长度”
假设你喝水,水杯里刚開始有一升水。你每次喝掉一百毫升。那么你喝掉两百毫升的状态和喝掉三百毫升的状态相比,喝掉三百毫升的这个状态“深度更大”。
假设你在走地图,从(0,0)開始,一次走一步。
那么你位于(2。3)的状态和你位于(4,5)的状态相比,(4,5)的这个状态“深度更大”
明确什么叫深度。那么DFS,也就是深度优先搜索的概念就能够明确了。
对于当前状态n。假设找到一个满足条件的下一个状态m,无论接下来还有没有符合条件的状态,都開始对m进行搜索。假设当前状态没有符合条件的下一个状态。就回溯到这个状态的上一个状态。
也就是说。假设m没有符合条件的下一个状态点,就继续对n进行搜索。
那么能够用伪代码表示为:
//对于状态a进行推断
int fun(status a)
{
    if(a是结束条件)
    {
        找到解,进行操作
    }
    for(进行寻找)
    {
        if(找到了符合条件的下一个状态b)
        {
            //对B进行推断
            fun(b);
        }
    }
    找不到符合条件的状态。退出函数,返回到上一层。
}
那么对于果园的地图,我们的部分状态是这样的: 
S 0 1 1 0 
0 1 0 0 0 
0 0 1 1 0 
0 1 0 0 0 
0 0 0 0 G
从S点開始,设S点坐标为(1,1)
(1,1) 
->(1,2) 
->(1,1)(注意,这里回溯到了(1,1)点) 
->(2,1) 
->(3,1) 
->(3,2) 
->(3,1)(回溯到3,1点) 
->(4,1) 
->(5,1) 
…… 
->(5,5)
可是要注意,DFS由于递归调用。时间复杂度会非常高(平均时间(N^3*1/3)),所以要注意优化的技巧。
最经常使用的就是剪枝。对于这道题目来说,对于訪问过的点不再进行二次訪问,减小递归层数,就是剪枝的一种表现。
至于其它技巧…… 这些还是自己摸索的靠谱。
对于每种找到结果的方案,记录步数,最后便可获得最小的步数。可是,假设要记录获取最小步数的整个过程。DFS就显得力不从心,由于递归调用的问题。DFS并不能保证自己得到的当前解就是最优的解。
所以,DFS适合用来推断某个状态是否能达到,或者能够有多少种方案取得终于解。不适合用来做状态记录。
而针对单个最优解和状态记录,更为合适的方法是BFS。
代表题目:N皇后问题
N皇后问题是一个经典的问题,在一个N*N的棋盘上放置N个皇后,每行一个并使其不能互相攻击(同一行、同一列、同一斜线上的皇后都会自己主动攻击)。
#include<stdio.h>
#define N 15   
int n; //皇后个数
int sum = 0; //可行解个数
int x[N]; //皇后放置的列数   
int place(int k)
{
    int i;
    for(i=1;i<k;i++)
      if(abs(k-i)==abs(x[k]-x[i]) || x[k] == x[i])
        return 0;
    return 1;
}   
int queen(int t)
{
    if(t>n && n>0) //当放置的皇后超过n时,可行解个数加1。此时n必须大于0
      sum++;
    else
      for(int i=1;i<=n;i++)
      {
          x[t] = i; //标明第t个皇后放在第i列
          if(place(t)) //假设能够放在某一位置,则继续放下一皇后
            queen(t+1);
      }
    return sum;
}   
int main()
{
    int t;
    scanf("%d",&n);
    t = queen(1);
    if(n == 0) //假设n=0。则可行解个数为0,这样的情况一定不要忽略
      t = 0;
    printf("%d",t);
    return 0;
}  
步步为营(十五)搜索(一)DFS 深度优先搜索的更多相关文章
- HDU 1241 Oil Deposits DFS(深度优先搜索) 和 BFS(广度优先搜索)
		
Oil Deposits Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total ...
 - HDU 4707 Pet(DFS(深度优先搜索)+BFS(广度优先搜索))
		
Pet Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submissio ...
 - 利用广度优先搜索(BFS)与深度优先搜索(DFS)实现岛屿个数的问题(java)
		
需要说明一点,要成功运行本贴代码,需要重新复制我第一篇随笔<简单的循环队列>代码(版本有更新). 进入今天的主题. 今天这篇文章主要探讨广度优先搜索(BFS)结合队列和深度优先搜索(DFS ...
 - 回溯算法 DFS深度优先搜索 (递归与非递归实现)
		
回溯法是一种选优搜索法(试探法),被称为通用的解题方法,这种方法适用于解一些组合数相当大的问题.通过剪枝(约束+限界)可以大幅减少解决问题的计算量(搜索量). 基本思想 将n元问题P的状态空间E表示成 ...
 - 采用邻接矩阵表示图的深度优先搜索遍历(与深度优先搜索遍历连通图的递归算法仅仅是DFS的遍历方式变了)
		
//采用邻接矩阵表示图的深度优先搜索遍历(与深度优先搜索遍历连通图的递归算法仅仅是DFS的遍历方式变了) #include <iostream> using namespace std; ...
 - 『ACM C++』HDU杭电OJ | 1416 - Gizilch (DFS - 深度优先搜索入门)
		
从周三课开始总算轻松了点,下午能在宿舍研究点题目啥的打一打,还好,刚开学的课程还算跟得上,刚开学的这些课程也是复习以前学过的知识,下半学期也不敢太划水了,被各种人寄予厚望之后瑟瑟发抖,只能努力前行了~ ...
 - matlab练习程序(广度优先搜索BFS、深度优先搜索DFS)
		
如此经典的算法竟一直没有单独的实现过,真是遗憾啊. 广度优先搜索在过去实现的二值图像连通区域标记和prim最小生成树算法时已经无意识的用到了,深度优先搜索倒是没用过. 这次单独的将两个算法实现出来,因 ...
 - [算法总结]DFS(深度优先搜索)
		
目录 一.关于DFS 1. 什么是DFS 2. DFS的搜索方式 二.DFS的具体实现 三.剪枝 1. 顺序性剪枝 2. 重复性剪枝 3. 可行性剪枝 4. 最优性剪枝 5. 记忆化剪枝 四.练习 一 ...
 - 搜索与图论①-深度优先搜索(DFS)
		
深度优先搜索(DFS) 例题一(指数型枚举) 把 1∼n 这 n 个整数排成一行后随机打乱顺序,输出所有可能的次序. 输入格式 一个整数 n. 输出格式 按照从小到大的顺序输出所有方案,每行 1 个. ...
 
随机推荐
- 74.QT窗口实现类的封装
			
#include "mainwindow.h" #include <QApplication> #include <windows.h> //定义一个窗口类 ...
 - POJ 3038 贪心(multiset)
			
题意: 思路: 1. 贪心 我们考虑肯定是走最近的最合适 想象自己是一个黑一日游的司机: 1.如果有乘客要上车,那么就让他上,收钱! 2.如果超载了,把距目的地最远的几个乘客踢下去,退钱. 3.行驶到 ...
 - 洛谷P3383 【模板】线性筛素数(Miller_Rabin)
			
题目描述 如题,给定一个范围N,你需要处理M个某数字是否为质数的询问(每个数字均在范围1-N内) 输入输出格式 输入格式: 第一行包含两个正整数N.M,分别表示查询的范围和查询的个数. 接下来M行每行 ...
 - 【IOS学习】1.第一个IOS程序
			
1.执行原理 a.首先执行main函数 调用UIApplicationMain方法 return UIApplicationMain(argc, argv, nil, NSStringFromClas ...
 - Entity Framework的原理及使用方式
			
ADO.NET Entity Framework操作数据库的过程对用户是透明的(当然我们可以通过一些工具或方法了解发送到数据库的SQL语句等).我们唯一能做的是操作EDM,EDM会将这个操作请求发往数 ...
 - Kinect开发 —— 基础知识
			
转自:http://www.cnblogs.com/yangecnu/archive/2012/04/02/KinectSDK_Application_Fundamentals_Part2.html ...
 - 2017国家集训队作业[arc076d/f][Exhausted?]
			
2017国家集训队作业[arc076d/f][Exhausted?] 题意:  有\(N\)个人,\(M\)把椅子,给出\(...L_i.R_i\)表示第\(i\)个人可以选择编号为\(1\sim ...
 - VS Code 终端显示问题
			
一.打开编辑器的终端时候,然后弹出了系统自带的cmd窗口 解决办法: Win+R 输入cmd 打开windows cmd窗口,窗口顶部右键属性,然后取消勾选使用旧版控制台,然后重启编辑器就行了. 二. ...
 - 查看JSP和Servlet版本+
			
如何查看JSP和Servlet版本 找到jsp-api.jar和servlet-api.jar ,分别打开META-INF下的MAINMEFT.MF文件,查看对应的版本. 例: JSP版本: Mani ...
 - colrm---删除文件制定列