以下是本人对回朔法与动态规划的思考,不当之处还请轻喷指正,谢谢!
回朔法与动态规划可以说是在某种程度上两种截然不同对立的方法:回朔法从头考虑结果,而动态规划从结果着手考虑;回朔法一般用递归实现,而动态规划一般是循环实现;回朔法耗时、效率低,而动态规划运行速度快、效率高;回溯法很容易保存路径,而动态规划却不易保存路径。
举个例子:求一组正整数中能否由一个或几个元素相加,结果和等于给定值(简单考虑,假设元素这些正整数的值都是小于等于给定值的)
回朔法代码如下示:
void addToTarget(vector<int >&v,int n,int target,int sum,int index,bool &result)//调用时addToTarget(v,n,target,0,0,result);{
if(result)
return;
if(sum==target)
{
result=true;
return;
}
if(index<n)
{
addToTarget(v,n,target,sum+v[index],index+1,result);//当前index下标元素加到sum里的情况
addToTarget(v,n,target,sum,index+1,result);//当前index下标元素不加到sum里的情况
}
}
可以看出,这是01背包问题,条件就是恰好等于给定值,动态规划的代码如下示:
void addToTarget(vector<int >&v,int n,int target,bool &result)//调用时addToTarget(v,n,target,result);
{
int i,j,sum=0;
int dp[target];
memset(dp,0,sizeof(dp));
dp[0]=1;
for(i=0;i<n;++i)
{
for(j=target;j>=v[i];--j)
{
if(dp[j-v[i]])
dp[j]=1;
if(dp[target])
{
result=true;
return;
}
}
}
}
所以,当用回溯法不能很好滴解决问题(比如运行超时)时,可以逆向考虑一下动态规划;当用动态规划可以很快滴判定是否有解,但如果需要保存路径时,这是就可以考虑用回朔法来代替动态规划了。
比如下面这个例子用回朔法是超时的,但是用动态规划就Ok了---------------------leetcode上的https://leetcode.com/problems/house-robber/
回溯法代码:
class Solution {
public:
void robmoney(vector<int>&v,int n,int index,int sum,int &max)
{
if(index>=n)
{
if(sum>max)
max=sum;
return;
}
robmoney(v,n,index+2,sum+v[index],max);
robmoney(v,n,index+1,sum,max);
}
int rob(vector<int> &num) {
if(num.size()<1)
return 0;
if(num.size()==1)
return num[0];
int max=INT_MIN;
robmoney(num,num.size(),0,0,max);
return max;
}
};
动态规划代码:
class Solution {
public:
int rob(vector<int> &num) {
if(num.size()<1)
return 0;
if(num.size()==1)
return num[0];
int i,j,n=num.size(),max;
int dp[n];
dp[0]=0;
dp[1]=num[0];
max=dp[1];
for(i=2;i<=n;++i)
{
if(dp[i-1]>(dp[i-2]+num[i-1]))
dp[i]=dp[i-1];
else
dp[i]=dp[i-2]+num[i-1];
if(dp[i]>max)
max=dp[i];
}
return max;
}
};