[复习]深度优先搜索

深度优先搜索(dfs)是利用递归完成的以搜索深度优先的搜索

通常大概是这样的:

 1 void search(int vi){
 2     if( 达到目标 ){ //边界
 3         if( 不满足要求 ) return ;
 4         //(和最优解比较)
 5         //当比当前最优解更优时
 6         //更新当前最优解
 7         return ;//必须返回
 8     }
 9     for( int i = ...; i <= ... ; i++ ){ //枚举
10         //保存结果
11         search(vi);
12         //清除刚刚保存的结果
13     }
14 } 

特点:

1.内存消耗小(不像广搜需要保存节点数)

2.题目的数据范围较小(例如noip普及组某年的一道题“子矩阵”)

3.耗时较长(函数的调用和返回会耗时,盲目地去枚举所有情况)

4.无法处理深度不能确定的题(例如vijos 埃及分数)

上面提到了耗时较长的问题,这对noip通常是1s限时,貌似会有几组数据会超时,

但是经常是有一些不可能是最优解的内容,计算机却只是一个忠实执行者,

原封不动地照着代码运行。

比如部落卫队(可以去搜搜这道题),如果现在已经选了的人再加上所有还没有

考虑的人都还是比最优解的人数少,就一定不能更新最优解,这时候就需要返回,

不再进行盲目的搜索。

剪枝:

剪枝就是指的是把不可能成为最优解的“枝干”减去,虽说说起看起很高端的样子

事实上大多数情况,只用一个return语句和一个if语句就可以完成这项工作

  if( 不可能更新最优解 ) return ;

剪枝还有一些注意事项:

1.正确性

  如果剪枝不正确的话虽然可能速度提升了很多,但是会导致最终的答案出错

2.必要性

  有些地方去判断剪枝实际上会浪费更多的时间开销,即使这样剪枝有时候也

可能并没有对时间复杂度有显著的降低。

  例如noip的Mayan游戏,虽然当游戏中只剩1、2个方块时就没有必要继续搜索,

但是遇到这种情况比较少,而且深度也比较低(最高为5),如果用vertor,也没有

浪费过多的时间,这样剪枝只是稍微提高了一下速度,但在每次去统计也会耗费较

多的时间

下面附上用动态规划 + 深搜完成的“子矩阵”

Code:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #define _min(a,b) (a<b)?(a):(b)
 5 #define _abs(a) (a<0)?(0-(a)):(a)
 6 using namespace std;
 7 typedef bool boolean;
 8 //FILE *fin =fopen("submatrix.in","r");
 9 //FILE *fout=fopen("submatrix.out","w");
10 int map[18][18];
11 int n,m;    //行 列
12 int r,c;    //行 列
13 int *lines;
14 int *rows;
15 long long minx = 10000000;            //最优解
16 long long getSubMatrix(int line,int newLine){    //计算新增加的值
17     long long result = 0;
18     for(int i=0;i<r-1;i++){
19         result += _abs(map[rows[i]][newLine] - map[rows[i+1]][newLine]);        //行与行之间的差值
20     }
21     if(line>0){
22         for(int i=0;i<r;i++){
23             result += _abs(map[rows[i]][newLine] - map[rows[i]][line]);//列与列之间的差值
24         }
25     }
26     return result;
27 }
28 void getLine(/*int last,int ps,int sum*/){
29 //    if(sum>=minx) return ;
30 //    if(ps==c){
31 //        minx=sum;
32 //        return ;
33 //    }
34 //    for(int i=last+1;i<=(m-c+ps+1);i++){
35 //        lines[ps]=i;                                //保存行
36 //        getLine(i,ps+1,sum+getSubMatrix(ps,i));
37 //    }
38     int f[18][18];
39     int s[18][18];
40     for(int i=1;i<=m;i++)
41         for(int j=1;j<=m;j++){
42             if(i==j) continue;
43             s[i][j]=getSubMatrix(i,j);
44         }
45     memset(f,0x7f,sizeof(f));
46     for(int i=1;i<=m;i++) f[1][i]=getSubMatrix(0,i);
47     for(int i=2;i<=c;i++){
48         for(int j=i;j<=m;j++){
49             for(int k=i-1;k<j;k++){
50                 f[i][j]=_min(f[i][j],f[i-1][k]+s[k][j]);
51             }
52         }
53     }
54     for(int i=1;i<=m;i++)
55         minx=_min(f[c][i],minx);
56 }
57 void getRow(int last,int ps){                    //搜索行
58 //    if(now>n&&ps!=r) return ;                    //边界
59 //    if((ps+(n-now)+1)<r) return ;                //剪枝
60     if(ps==r){                                    //搜索到了指定数量的行数
61 //        getLine(0,0,0);                            //搜索列
62         getLine();
63         return ;
64     }
65     for(int i=last+1;i<=(n-r+ps+1);i++){
66         rows[ps]=i;                                //保存行
67         getRow(i,ps+1);
68     }
69 //    getRow(now+1,ps+1);
70 //    getRow(now+1,ps);
71 }
72 int main(){
73 //    fscanf(fin,"%d%d%d%d",&n,&m,&r,&c);
74     scanf("%d%d%d%d",&n,&m,&r,&c);
75     rows=new int[(const int)(r+1)];                //指针的初始化
76     lines=new int[(const int)(c+1)];
77     for(int i=1;i<=n;i++){
78         for(int j=1;j<=m;j++){
79         //    fscanf(fin,"%d",&map[i][j]);        //读入数据
80             scanf("%d",&map[i][j]);
81         }
82     }
83     getRow(0,0);                                //开始搜索
84 //    fprintf(fout,"%ld",minx);
85     printf("%ld",minx);
86     return 0;
87 }
时间: 2024-10-10 10:13:46

[复习]深度优先搜索的相关文章

Java 实现广度优先搜索和深度优先搜索

1. 综述 复习算法数据结构,用Java 实现广度优先搜索和深度优先搜索. 2. 代码 要搜索的图为: Java代码: 1 package cn.edu.tju.scs; 2 3 import java.util.LinkedList; 4 import java.util.Queue; 5 6 public class Search { 7 public static boolean [] accessed = new boolean[8]; 8 public static boolean [

有关搜索和深度优先搜索的浅陋见解

祝食用愉快XD 题目链接 (是一道胡乱出的题) U56815 来走迷宫鸭! 解题思路 深度优先搜索,如果能不碰墙地到达右下角的出口,就把旗子立起来表示找到了出口. 什么?你没听过深度优先搜索 没事,且听我道来. 什么是搜索?如何搜索? 简单来说,搜索就是一种特殊的(递归的)枚举.从一种可行的方案进行扩展,并去看这个扩展出来的东西符不符合现有规则.能不能继续扩展. 可是你讲理论我也听不懂啊 那,深度优先搜索又是什么呢? 拿走迷宫这事儿说起.如果你玩过\(MC\),或者无论从哪个去掉了解走迷宫的时候

深度优先搜索与广度优先搜索算法理解

深度优先搜索算法和广度优先搜索算法是图论中两个有意思也很实用的算法,下面我们来看看这两个算法. 严书中,给出的利用深度优先搜索(Deep First Search)算法进行图的遍历伪码如下 1 Boolean visited[MAX]; //标志数组 2 Status (*VisitFunction)(int v); //访问函数 3 4 void DFSTraverse(Graph G, Status (*Visit)(int v)) 5 { 6 VisitFunction = Visit;

图论 深度优先搜索 广度优先搜索的非递归实现

深度优先遍历 1.深度优先遍历的递归定义 假设给定图G的初态是所有顶点均未曾访问过.在G中任选一顶点v为初始出发点(源点),则深度优先遍历可定义如下:首先访问出发点v,并将其标记为已访问过:然后依次从v出发搜索v的每个邻接点w.若w未曾访问过,则以w为新的出发点继续进行深度优先遍历,直至图中所有和源点v有路径相通的顶点(亦称为从源点可达的顶点)均已被访问为止.若此时图中仍有未访问的顶点,则另选一个尚未访问的顶点作为新的源点重复上述过程,直至图中所有顶点均已被访问为止. 图的深度优先遍历类似于树的

深度优先搜索

在图中的深度优先搜索,由于避免回路的产生,设置visit数组. 有两种深度优先的应用场景.一种是用于最优解的寻找,即到达目的地的最优解.这时需要设置全局的一个数组,还有变量,来储存路径.通过与别的方法的比较,获取最优解. 第二种是染色问题,只要求全部遍历,没有最优的要求. 还有哈希的用法.当需要记录拥有共同数字特征的一些属性时,就可以使用哈希数组.使用时按照属性的含义寻找.如二叉树某层的数量.

深度优先搜索(dfs)

关于深度优先搜索的总结: 1 dfs 的基本结构:  void dfs(int x){ if( x 超出边界){ return ; }else{ for(遍历){ if(未访问过){ 访问         ; 打上标记    ; dfs(x + 1) ; 去掉标记    ; //极易忘记 } } } return; } 2 用dfs求全排列: 本来好好的,结果sizeof(pointer) 就完蛋了.神秘的内存错误,而且还能正常的跑出一个不正常的结果出来. 想了解sizeof这个小妖精的看这里

深度优先搜索思想初体验

1.求数字 1~n 的全排列 import java.util.Scanner ; public class Permutation{ //求数字 1~n 的全排列: int[] array ; int[] book ; int n ; public void permutation(int step){ // 深度优先搜索思想: if (step==n+1) { for (int i=1;i<=n;i++) { System.out.print(array[i] + " ")

深度优先搜索(DFS)

定义: (维基百科:https://en.wikipedia.org/wiki/Depth-first_search) 深度优先搜索算法(Depth-First-Search),是搜索算法的一种.是沿着树的深度遍历树的节点,尽可能深的搜索树的分支.当节点v的所有边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点.这一过程一直进行到已发现从源节点可达的所有节点为止.如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止(属于盲目搜索). 基

图的遍历之深度优先搜索(DFS)

深度优先搜索(depth-first search)是对先序遍历(preorder traversal)的推广.”深度优先搜索“,顾名思义就是尽可能深的搜索一个图.想象你是身处一个迷宫的入口,迷宫中的路每一个拐点有一盏灯是亮着的,你的任务是将所有灯熄灭,按照DFS的做法如下: 1. 熄灭你当前所在的拐点的灯 2. 任选一条路向前(深处)走,每经过一个拐点将灯熄灭直到与之相邻的拐点的灯全部熄灭后,原路返回到某个拐点的相邻拐点灯是亮着的,走到灯亮的拐点,重复执行步骤1 3. 当所有灯熄灭时,结束 将