算法期末備考-第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('\n');
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\n",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\n",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\n");
 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('\n');
 94         }
 95         putchar('\n');
 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\n",cur.step );
31 32             //輸出變化的過程
33             for( int i = 0 ; i < cur.step ; i ++ )
34                 printf("%c",cur.path[i]);
35             putchar('\n');
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  
整數變換問題
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM