zoukankan      html  css  js  c++  java
  • [复习]深度优先搜索

    深度优先搜索(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 }

     

  • 相关阅读:
    校园活动管理-毕业设计
    Golang时间字符串转换计算器
    5.21 Go秘籍:异步收割,永葆单身
    Golang东北之旅—channel
    Python3下载豆瓣音乐人小站音乐
    一张图记住4种树
    人生如锁
    Golang构造二叉树解决整数排序问题
    用Golang单元测试写作文
    Golang定时任务表达式合法性校验
  • 原文地址:https://www.cnblogs.com/yyf0309/p/5657350.html
Copyright © 2011-2022 走看看