zoukankan      html  css  js  c++  java
  • 算法期末备考-第1练-分支界限法

    算法期末备考-第1练 

    考虑到 大家针对备考 算法无从下手。

    同时算法是最后一门考试科目,可能复习比较匆忙就考试了。

    从今天开始每天进行一练,希望大家每天花上至少一个小时来复习,只要大家重视起这门课,就不会挂科。

     

    算法是以理解为基础。

    “理解是最好的记忆”

    不要背代码,不要背代码,不要背代码。

    等你理解算法核心后,做题和复习起来才会胸有成竹

     

    内容主要分为

    1、掌握算法基本思路

    2、历年真题

    3、课后习题

     

    如果发现代码有错误或者有疑问请及时联系我。

    放在博客上,主要是因为比较容易修改。

     

    不用光顾着看,大脑非常容易欺骗自己,大家必须动手实践一下。

    道理就好比记单词。

     

    建议:

    通过热身环节后,大家自己试着写一下后面的题目。

    如果遇到不会才看参考代码,千万不要先入为主直接背代码,这样效率低而且容易忘。

     

    热身环节 

    子集树问题

     

    题目描述:

      给定3个元素的一个集合,输出对应的所有子集的情况。

      3个元素构成的子集为2^3=8种情况。

      分别为“111,110,101,100,011,010,001,000”

    题解:

      面对子集的问题有很多种解法,其中一种方法为BFS,对于这颗搜索树来说是层次遍历。

      顺带借助子集树问题来介绍一下BFS算法。

      

      介绍

      BFS 是 Breadth first Search 的首字母组合。

      中文翻译回来是“宽度优先搜索”

      在这个题目中就相当于"层次遍历",一层一层地遍历,其字母顺序为:“A,BC,DFGH,IJKLMNO”。

      算法过程

      过程中利用到了数据结构“队列”利用其先进先出的特性。

      请大家拿出草稿纸模拟其中过程。

      1、把根节点A放入队列。

      2、弹出队首结点,同时将  队首结点的左右两个结点依次放入队列。

      3、重复第二步就能实现层次遍历。

      1、A

      2、“A”   |  'BC'

      3、“B”   |  C'DE'

      4、“C”   |  DE'FG'

      ……

      图示:

      弹出队首用“”表示。

      新加入队列的元素用''表示。

      " | " 后面的是当前队列中的元素。

     


      前置知识:

      过程中需要用到队列,在此之前必须要知道如何定义队列中元素的属性。

      “属性”,其实根据题目来说的,

      通常根据题目进行加属性。

      如果是搜索树,以树为结构的必定要有一个变量作为层数   我常用Step来表示。

      如迷宫类问题,必须有用于定位的坐标"int x,y"。

      如果是背包问题,每个结点表示都是一种状态,每个背包都有自身的价值和重量。“int 价值:val,重量:w”

      如果是整数变换问题,每个结点都有各自的值。“int x”

      如果题目需要记录对应的路径,则定义“ char path[N]”

    typedef struct Node{
        int step ;
        char path[N];
    }Node;

      然后是C++库中提供的STL库中的queue

    #include<queue>         //对应的头文件
    using namespace std;    //利用STL库一定记住要写上"命名空间"
    
    <queue>
    
    //定义
    queue<Node>Q;           //定义存放Node类型队列,其名为"Q"
    
    //库函数
    Q.push( (Node)*** );    //把Node类型变量,插入到Q的队尾
    Node t = Q.front();     //将队首元素进行赋值给Node类型的变量t
    Q.pop();                //弹出队首元素
    Q.empty();              //判断当前的队列中是否为空? 返回bool类型 , 若是真的为空,返回true,否则返回 false

      算法实现的大体思路:

      将队列中队首结点拿出来,判断其结点是否为叶子结点。

        1、如果为叶子结点,输出叶子结点中的路径

        2、否则,把自己与其相连的两个孩子结点给插入到队列后面。

      然后具体套路模版上课已经讲过,如果忘记了的同学可以看看下面的代码复习一下具体过程。

    代码链接:https://pasteme.cn/25521

     

     1 //子集树
     2  3 #include<queue>
     4 #include<cstdio>
     5 using namespace std;
     6  7 //定义结点记录信息
     8 typedef struct Node{
     9     char path[6];
    10     int step ;
    11 }Node;
    12 13 // BFS套路
    14 void BFS(){
    15 16     //第一步:定义根节点和队列,并把根节点压入队列
    17     queue<Node> Q ;
    18     Node first ;
    19     first.step = 0 ;
    20     Q.push(first) ;
    21 22     //第二步:保持队列非空
    23     while( !Q.empty() ){
    24 25         //第三步:取出队首元素,别忘了同时要弹出队首元素
    26         Node cur = Q.front() ;
    27         Q.pop() ;
    28 29         //第四步:设计 最终状态 进行的操作
    30         if( cur.step == 3 ){
    31             for( int i = 1 ; i <= 3 ; i ++ ){
    32                 printf("%c",cur.path[i]);
    33             }
    34             putchar('
    ');
    35             continue ;
    36         }
    37 38         //第五步:设计 下一步怎么走,用"Next"来命名下一步结点,压入队尾
    39 40         Node Next = cur ;
    41         Next.step += 1 ;
    42 43         //走左边
    44         Next.path[ cur.step + 1 ] = 'L' ;
    45         Q.push( Next );
    46 47         //走右边
    48         Next.path[ cur.step + 1 ] = 'R' ;
    49         Q.push( Next );
    50     }
    51 }
    52 53 int main()
    54 {
    55     BFS();
    56     return 0;
    57 }
    子集树问题

     


     

    历年真题

    01背包问题

    题目描述:

      有一个背包容量为30;同时有三个物品<value,weight>为<45,16>,<25,15>,<25,15>

      请问,对于背包能承受的最大重量来说,背包的最大价值为多少?

    题解:

      以子集树为基础,每个结点只是多了价值和重量。

      但是非叶子结点在放入物品时必须必须要加上限制条件,必须是背包能放入的情况下才插入队尾。

    代码链接:https://pasteme.cn/25528

     

     1 //01背包问题
     2  3 #include<queue>
     4 #include<cstdio>
     5 #include<algorithm>
     6 using namespace std;
     7  8 //定义结点记录信息
     9 typedef struct Node{
    10     int val , w ;
    11     int step ;
    12 }Node;
    13 14 int weight[3] = { 16 , 15 , 15 };
    15 int value[3] = { 45 , 25 , 25 };
    16 int V = 30 ;
    17 18 // BFS套路
    19 void BFS(){
    20 21     int n = 3 ;     // 物品个数
    22     int ans = 0 ;   // 答案
    23 24     //第一步:定义根节点和队列,并把根节点压入队列
    25     queue<Node> Q ;
    26     Node first ;
    27     first.step = first.val = first.w = 0 ;
    28     Q.push(first) ;
    29 30     //第二步:保持队列非空
    31     while( !Q.empty() ){
    32 33         //第三步:取出队首元素,别忘了同时要弹出队首元素
    34         Node cur = Q.front() , Next ;
    35         Q.pop() ;
    36 37         //第四步:设计 最终状态 进行的操作 <=> 到达叶子结点.
    38         if( cur.step ==  n ){
    39             ans = max( ans , cur.val );
    40             continue ;
    41         }
    42 43         //第五步:设计 下一步怎么走,用"Next"来命名下一步结点,压入队尾
    44         Next = cur ;
    45         Next.step += 1 ;
    46 47         //该操作为:物品不放进背包 <=> 子集树往左边走
    48         Q.push( Next );
    49 50         //该操作为:物品放入背包 <=> 子集树往右边走
    51         //前提是:保证物品能放入背包
    52         if( Next.w + weight[ cur.step ] <= V ){
    53             Next.w += weight[ cur.step ];
    54             Next.val += value[ cur.step ];
    55             Q.push( Next ) ;
    56         }
    57     }
    58     printf("%d
    ",ans);
    59 }
    60 61 int main()
    62 {
    63     BFS();
    64     return 0;
    65 }
    01背包问题

     

    布线问题

    题目描述:

      给定一个迷宫,其中白色为路,灰色为墙,每移动一格就说明距离加一,给定起点和终点。

      请问 a->b的最短距离为多少?

    题解:

      对于这类迷宫题目,记住

      定义结点是{x,y,step}的三元组,maze[][]迷宫路和墙的情况,vis[][]迷宫是否被访问,dir[4][2]方向数组

      向四个方向遍历时必须也要做到三个判断:

        1、不在边界,即(x,y)要合法

        2、maze[x][y]必须为路,如果时墙就走不过去。

        3、vis[x][y]看看x,y是否访问过。

      注意细节,然后到达终点提前结束即可。

             

    代码链接:https://pasteme.cn/25532

     

      1 //布线问题
      2   3 #include<queue>
      4 #include<cstdio>
      5 #include<algorithm>
      6 using namespace std;
      7   8 //定义结点记录信息
      9 typedef struct Node{
     10     int x , y ;
     11     int step ;
     12 }Node;
     13  14 int dir[4][2] = {
     15         {-1,0},
     16     {0,-1} , {0,1},
     17         {1,0}
     18 };
     19  20 int maze[9][9] ;
     21 int vis[9][9] ;
     22 int n = 9 , m = 9 ;
     23 int Sx,Sy , Ex,Ey ; //Start( x , y ) , End( x ,y )
     24  25 void Init(){
     26     maze[1][3] = maze[2][3] = maze[2][4] =
     27     maze[3][5] = maze[4][4] = maze[4][5] =
     28     maze[5][5] = maze[6][1] = maze[7][1] =
     29     maze[7][2] = maze[7][3] = maze[8][1] =
     30     maze[8][2] = maze[8][3] = 1;
     31  32     vis[1][3] = vis[2][3] = vis[2][4] =
     33     vis[3][5] = vis[4][4] = vis[4][5] =
     34     vis[5][5] = vis[6][1] = vis[7][1] =
     35     vis[7][2] = vis[7][3] = vis[8][1] =
     36     vis[8][2] = vis[8][3] = -1;
     37     Sx = 3 , Sy = 2 ;
     38     Ex = 4 , Ey = 7 ;
     39  40     //起点特定标记
     41     vis[Sx][Sy] = -1 ;
     42 }
     43  44 // BFS套路
     45 void BFS(){
     46  47     //是否能到达终点 的标记位
     48     bool flag = false ;
     49  50     //第一步:定义根节点和队列,并把根节点压入队列
     51     queue<Node> Q ;
     52     Node first = Node{ Sx , Sy , 0 } ;
     53     Q.push(first) ;
     54  55     //第二步:保持队列非空
     56     while( !Q.empty() ){
     57  58         //第三步:取出队首元素,别忘了同时要弹出队首元素
     59         Node cur = Q.front() , Next ;
     60         Q.pop() ;
     61  62         //第四步:设计 最终状态 进行的操作
     63         if( cur.x ==  Ex && cur.y == Ey ){
     64             printf("The Shortest Path : %d
    ",cur.step ) ;
     65             flag = true ;
     66             break ;
     67         }
     68  69         //第五步:设计 下一步怎么走,用"Next"来命名下一步结点,压入队尾
     70  71         for( int i = 0 ; i < 4 ; i++ ){
     72             int tx = cur.x + dir[i][0] ;
     73             int ty = cur.y + dir[i][1] ;
     74             if( ( 1 <= tx && tx <= n && 1 <= ty && ty <= m ) && maze[tx][ty] == 0 ){
     75                 if( vis[tx][ty] == 0 ){
     76                     vis[tx][ty] = cur.step + 1  ;
     77                     Next = Node{ tx , ty , cur.step + 1 } ;
     78                     Q.push( Next );
     79                 }
     80             }
     81         }
     82     }
     83     // 如果没有到达终点输出"Impossible"
     84     if( !flag ){
     85         printf("Impossible
    ");
     86     }
     87     // 输出BFS遍历路径
     88     else{
     89         for( int i = 1 ; i <= n; i ++ ){
     90             for( int j = 1 ; j <= m ; j++ ){
     91                 printf("%4d",vis[i][j]);
     92             }
     93             putchar('
    ');
     94         }
     95         putchar('
    ');
     96     }
     97 }
     98  99 int main()
    100 {
    101     Init();
    102     BFS();
    103     return 0;
    104 }
    布线问题

     

    课后习题

    整数变换问题

    题目描述:

    关于整数i的变换f和g定义如下:f(i)=3i,g(i)=i/2
    试设计一个算法,对于给定的2个整数n和m,用最少的变换次数将n变成m。
    输入:
    15 4 输出: 4 ggfg

    题解:

      其实这个问题跟子集树类似,问题虽然不知道答案落在哪一层。

      但是通过二叉树层次遍历即可,左边是:f()变换,右边是:g()变换

      只要遇到答案即可提前结束程序,注意该题目还需要加上路径记录。

     代码链接:https://pasteme.cn/25533

     1 //整数变换问题
     2 //关于整数i的变换f和g定义如下:f(i)=3*i,g(i)= i/2.
     3 //试设计一个算法,对于给定的2个整数n和m,用最少的变换次数将n变成m。
     4  5 #include<queue>
     6 #include<cstdio>
     7 #include<algorithm>
     8 using namespace std;
     9 10 //定义结点记录信息
    11 typedef struct Node{
    12     int x , step ;
    13     char path[30];
    14 }Node;
    15 16 int S = 15 , E = 4 ;
    17 void BFS( int S ){ // Start
    18 19     queue<Node> Q;
    20     Node first ;
    21     first.x = S ;
    22     first.step = 0 ;
    23     Q.push(first) ;
    24 25     while( !Q.empty() ){
    26         Node cur = Q.front() , Next ;
    27         Q.pop() ;
    28 29         if( cur.x == E ){
    30             printf("最少变换的次数: %d
    ",cur.step );
    31 32             //输出变化的过程
    33             for( int i = 0 ; i < cur.step ; i ++ )
    34                 printf("%c",cur.path[i]);
    35             putchar('
    ');
    36             break ;
    37         }
    38 39         Next = cur ;
    40         Next.x = cur.x * 3 ;
    41         Next.step += 1 ;
    42         Next.path[cur.step] = 'f' ;
    43         Q.push( Next );
    44 45         Next = cur ;
    46         Next.x = cur.x / 2 ;
    47         Next.step += 1 ;
    48         Next.path[cur.step] = 'g' ;
    49         Q.push( Next );
    50     }
    51 }
    52 53 int main()
    54 {
    55     BFS(S);
    56     return 0;
    57 }
    58  
    整数变换问题
     
     
  • 相关阅读:
    MVC3、如何应用EntityFramework 连接MySql 数据库 Kevin
    DEV EXPRESS Summary Footer 不显示 Kevin
    装饰模式 Kevin
    Dev 控件 GridControl 控件 二次绑定数据源的问题。 Kevin
    System.InvalidOperationException 异常 Kevin
    LINQ to XML Kevin
    代理模式——代码版“吊丝的故事” Kevin
    VS2012 中的设备 面板 Kevin
    maven 学习笔记(三)创建一个较复杂的 eclipse+android+maven 工程
    maven 学习笔记(一)eclipse+android+maven
  • 原文地址:https://www.cnblogs.com/Osea/p/12106718.html
Copyright © 2011-2022 走看看