这次练习主要针对的是“回溯法”

简单介绍一下,回溯法->深度优先搜索算法->dfs(Depth First Search)

所以个人习惯上都是对于任何需要回溯的问题,其函数命名为dfs。

 

深度优先搜索,本质上是对一颗搜索树进行搜索。

相较于BFS来说,DFS搜索顺序为“找到一个节点一直搜索到叶子结点,到了叶子再回头”

     算法期末备考-第2练-回溯法

 

  对于BFS顺序为:A,B,C,D,E,F,G……

  对于DFS顺序为:A,B,D,H,D,I,D,B,E,J,E,K,E,B,A……

 

BFS和DFS两者之间:

1、dfs相较于bfs比较方便好使,因为过程不借助队列

2、如果同一个问题用bfs和dfs都能实现情况下,通常用bfs,

原因有:搜索空间一定的情况下,dfs比bfs多了一步回溯的操作。

针对搜索树中每一个节点来说,bfs只遍历一遍,但是dfs需要回溯回来。

例如迷宫问题明显时BFS优势大。

 


 

对于期末考试考查以下三种能力

 

1、子集树(01背包问题,幻方数)

2、排列树(TSP问题)

3、类多叉树遍历(李白打酒,n皇后)

 


 

热身环节 

子集树

算法本质

  顾名思义,利用集合的思路进行操作。

  集合有三种性质,(无序性,互异性,确定性)

  在求解过程中,利用更多的是“互异性” (即集合中不存在两个相同的元素)。

 

引入问题

01背包

 

  算法期末备考-第2练-回溯法

 

 

问题描述:

  对于给定一个背包,其背包有一定的承重能力,给出有n个物品,物品以<value,weight>形式出现。

  请问在背包承重范围内,实现背包的最大价值。

题解:

  假定 每个物品“取和不取” => 取 <-> '1' 不取 <-> '0'

  然后对于3个物品的背包问题共有2^3=8种情况,如下所示

 

(000) -> {}

(001) -> {1}

(010) -> {2}

(011) -> {1,2}

(100) -> {3}

(101) -> {1,3}

(110) -> {2,3}

(111) -> {1,2,3}

 

  由于集合的互异性,每次在物品放与不放时,都需要判断当前集合中是否存在物品。

  我们需要借助一个标记数组来进行操作

  标记数组名可以为“vis(visit)” , "book" , "st(state)" , "used"

  问题转化为:构建一颗搜索树,高度为n层,每一个节点都表示背包状态,

  同时每一层都是表示物品放和不放,若走左子树<->物品放,否则走右子树<->物品不放。

  答案即为:所有叶子结点的最小值.

 


 

 1 //dfs子集树解决01背包问题
 2 #include<cstdio>
 3 #include<algorithm>
 4 using namespace std;
 5 const int N = 5;
 6  7 int value[] = { 45 , 25 , 25 };
 8 int weight[] = { 16 , 15 , 15 };
 9 int V = 30 ;
10 11 int n = 3 ;         //物品数量
12 int ans ;           //答案
13 int val , w ;       //每个结点中<value,weight>的状态
14 int vis[N] ;        //物品标记状态
15 16 void dfs( int step ){
17 18     //到达叶子结点
19     if( step == n ){
20         ans = max( ans , val );
21         return ;
22     }
23 24     //物品不在背包中,且放物品后还在背包承受范围内.
25     if( vis[step] == 0 && w + weight[step] <= V){
26         //对于第Step个物品进行标记,同时更新结点对应的<val,w>状态
27         vis[step] = 1 ;
28         w += weight[step] ;
29         val += value[step] ;
30 31         //往左子树走
32         dfs( step + 1 );
33 34         //回溯,返回结点后需要把第step个物品取出来,
35         //同时恢复 结点对应的<val,w>状态
36         val -= value[step] ;
37         w -= weight[step] ;
38         vis[step] = 0 ;
39     }
40     //往右子树走
41     dfs( step + 1 );
42 }
43 44 int main()
45 {
46     dfs(0) ;
47     printf("%d\n",ans);
48     return 0 ;
49 }
子集树-01背包问题

相关文章:

  • 2022-02-03
  • 2021-11-23
  • 2021-08-06
  • 2021-08-10
  • 2021-12-18
  • 2022-01-15
  • 2021-04-02
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-01-11
相关资源
相似解决方案