回溯法和动态规划的一般模板

Posted limancx

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了回溯法和动态规划的一般模板相关的知识,希望对你有一定的参考价值。

1.回溯法

回溯法的基础题目类型就是子集树和排列树,掌握最基础的模板,那么其它的题目都可以在此上变形得到,子集树即如下图所示:

技术图片

 

 

 同一个元素不能被选入多次,子集树的算法模板为

 1 void Backtrack(int t) {     //t 表示当前是树的第t层,即对集合 S 中的第 t 个元素进行判断
 2     if (t > n)
 3         output(x);          //大于S中总的元素个数 ,遍历完成 
 4     else
 5         for (int i = 0; i < = l; i++) {     // 两种可能 加入或者不加入到解集合 
 6             x[t] = i;
 7             if (Constraint(t) && Bound(t)){     //满足约数条件  
 8                     Backtrack(t + 1);           //对 t+1 层进行判断 
 9                 } 
10         }
11 }

还有就是排列树,排列树即

技术图片

 

 

 这种,即一个元素可以多次被选择,排列树的模板为

 1 void Backtrack(int t) {     //t 表示集合 S 的第 t 个元素 
 2     if (t > n)
 3         output(x);
 4     else
 5         for (int i = t; i <= n; i++) {      //第t 个元素与其后面的所有元素进行交换位置 
 6             swap(x[t], x[i]);
 7             if (constraint(t) && bound(t)){ 
 8                     backtrack(t + 1);
 9                 } 
10             swap(x[t], x[i]);
11         }
12 }

在回溯法的问题中,只要在这两种基础的模板上变形即可。

2.动态规划

动态规划问题相对来说有一点难度,这里可以帮助给出动态规划的一般思路:

首先确定问题符合动态规划问题的一般条件,即无后效性、最优子结构性质和重叠子问题性质。一般我们可以这样理解,如果你想构造一个一维或二维dp数组,如果当前要决策的变量dp[i]的值跟后面的决策无关(无后效性),仅仅和前面的某个或者某几个dp[j](其中j为小于i的值)有关,且dp[j]也是之前第j个决策变量决策时的最优选择(最优子结构性质),同时由决策dp[j]时的状态转移到dp[i]的状态的转移策略和dp[i]转移到dp[k](其中k大于i)的状态转移策略是相同的,那么这时候就适合用动态规划算法。

动态规划算法和贪心算法的不同之处在于,贪心算法往往只跟当前状态有关,而动态规划是不仅仅和当前状态有关,并且和之前的某些状态有关的。

当确定可以使用动态规划算法后,就要确定这个dp数组中每一个元素可能的取值,即可能有的决策方案或者状态值;

然后动态规划算法的最重要的就是提取状态转移方程,一个可以参考的做法是考虑某个决策变量/状态dp[i]和前面的哪些状态有关,即先找到dp[i]和dp[j]、dp[m]、dp[n]这些先前状态的位置,也即j、m、n可能的取值,然后要确定j,m,n怎么由i得到,比如j可能是i-1,m可能是i-2,n可能是i-dp[i-1],此时已经确定dp[i]和哪些状态有关系了。接下来,就是确定怎么由dp[j],dp[m],dp[n]得到dp[i],也就是状态转移方程,一般就是根据当时的状态dp[j]以及经过了几个阶段后的影响change[j],然后求出每个有关的状态+影响,即dp[j]+change[j],dp[m]+change[m],以及dp[n]+change[n]多个取最优。

当对动态规划转移方程仍然不清晰时,可以手动采用表格法尝试一下模拟的过程。

动态规划的一般模板是

 1 int dynamicProgramming(int *state,int size)
 2 {
 3       int dp[size];
 4       dp[0] = initState;
 5       dp[1] = initState;
 6       for(int i = 2; i < size;++i)
 7       {
 8             int a = dp[i-1] + f(state[i],state[i-1] );
 9             int b = dp[i-2] + f(state[i],state[i-1] );
10             int c = dp[i-n] + f(state[i],state[i-n] );
11             dp[i] = best(a,b,c);
12       }
13       return dp[size-1];
14 }

以上是关于回溯法和动态规划的一般模板的主要内容,如果未能解决你的问题,请参考以下文章

六中常用算法设计:穷举法分治法动态规划贪心法回溯法和分支限界法

六中常用算法设计:穷举法分治法动态规划贪心法回溯法和分支限界法

动态规划回溯搜索分治算法分支限界算法

算法模板-回溯

算法模板-回溯

算法模板-回溯