为了让大家更好理解递归、回溯、动态规划三者算法之间有关系,本文罗列了几道题目,分别使用递归、回溯、动态规划解决。会发现三者之间同工异曲,都是一种搜索模式,递归是正向搜索且返回;回溯是搜索到尽头后你自己看着办、然后再继续;动态规划可以理解为反向搜索。
要有一定深度的理解,需要自己反复练习且揣摩其中的细节之分。
本文直接提出问题,直接给出答案。
一个专业的盗贼,计划偷打劫街的房屋。每间房内都藏有一定的现金,你可以进入每一间房子,影响偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被盗贼闯入,系统会自动报警。
现给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。
示例1:
输入:[1,2,3,1]
输出:4
解释:偷窃 1号房屋(金额=1),然后偷窃3号房屋(金额=3)。偷窃到的最高金额=1+3=4。
示例2:
输入:[2,7,9,3,1]
输出:12
解释:偷窃 1 号房屋(金额 = 2),偷 3 号房屋(金 = 9),接着偷 5 号房屋(金额 =1)偷窃到的最高金额=2+9+1=12。
#include
using namespace std;
//房间数量
int n;
//房间的金额
int m[100]={0};
int djjsDg(int idx) {
if(idx>n)return 0;
//偷, 进入下下个房间
int t= m[idx]+djjsDg(idx+2);
//不偷,可以直接进行相邻房间
int nt=djjsDg(idx+1);
return max(t,nt);
}
#include
using namespace std;
//房间数量
int n;
//房间的金额
int m[100]={0};
//结果
int maxVal=0;
/*
* sum 每次偷的金额
* idx 从第几间房间开始偷
*/
void djjsHs(int sum,int idx) {
for( int i=0; i<=1; i++ ) {
sum+= m[idx]*i;
if(idx>=n) {
//最后一家
maxVal=max(maxVal,sum);
} else {
//下一家
djjs(sum, i==0?idx+1:idx+2 );
}
sum-= m[idx]*i;
}
}
#include
#include
using namespace std;
//房间数量
int n;
//房间的金额
int m[100];
int dp[100]={0};
//结果
int res=0;
int main(int argc, char** argv) {
ios::sync_with_stdio(false);
cin>>n;
for(int i=1; i<=n; i++) {
cin>>m[i];
}
for(int i=1;i<=n;i++){
dp[i]=max( dp[i-1],m[i]+dp[i-2] );
res=max(res,dp[i]);
}
cout<
给你k
种面值的硬币,面值分别为c1, c2 ... ck
,每种硬币的数量无限,再给一个总金额amount
,问最少需要几枚硬币凑出这个金额,如果不可能凑出,算法返回 -1
。
比如说k = 3
,面值分别为 1,2,5
,总金额amount = 11
。那么最少需要 3
枚硬币凑出,即 11 = 5 + 5 + 1
。
#include
using namespace std;
int coins[5]= {1,5,10,21,25};
int money=10; //完全背包
// 记忆搜索
int cache[100]= {0}; //索引号:表示金额 值:结果,最少的硬币数
int zl(int m) {
int res=m;
//出口一的写法
//if(m==0)return 0;
//出口二的写法
for(int i=0; i<5; i++) {
if( m==coins[i] )return 1;
}
if(cache[m]!=0) {
res =cache[m];
} else {
//子问题有哪些(子节点有多少个)
for(int i=0; i<5; i++) {
if(coins[i]<=m ) {
res=min(res, 1+zl(m-coins[i]) ) ;
}
}
cache[m]=res;
}
return res;
}
#include
using namespace std;
//选择
int coins[5]= {1,5,10,21,25};
int money=10;
//结果
int res[100]= {0};
int minLen=money;
int show() {
int count=0;
for(int i=1; i<=money; i++) {
if(res[i]) {
count++;
cout<=coins[i] ) {
//选择
res[idx]= coins[i];
if( m-coins[i]==0 ) {
//显示结果
int res= show();
minLen=min(minLen,res);
} else {
//下一个流程
zlhs(idx+1,m-coins[i]);
}
res[idx]=0;
}
}
}
#include
#include
using namespace std;
int main(int argc, char** argv) {
int money=0;
cout<<"请输入零钱数:"<>money;
//硬币类型
int coins[5]= {1,5,10,21,25};
//状态数组,零钱需要找回的硬币数
vector dp(money+1, money+1);
dp[0]=0;
for(int i=1; i<=money; i++) {
for(int j=0; i>=coins[j]; j++) {
//求最小值
dp[i]=dp[i] < dp[ i-coins[j] ]+1 ? dp[i] : dp[ i-coins[j] ]+1;
}
}
cout<
0-1
背包有一个可装载重量为W
的背包和N
个物品,每个物品有重量和价值两个属性。其中第i
个物品的重量为wt[i]
,价值为val[i]
,现在用这个背包装物品,最多能装的价值是多少?
题目中的物品不可以分割,要么装进包里,要么不装,不能切成两块装一半。
如输入如下数据:
N = 3, W = 6
wt = [ 1,2,7 ]
val = [4,3,2 ]
可以选择前两件物品装进背包,总重量 3
小于W
,可以获得最大的价值是 7
。
#include
#include
using namespace std;
struct Goods {
//重量
int weight;
//价值
int price;
//物品状态 1 已经使用,0 未使用
int isUse;
};
//0 1 (不可分割,数量有限)
//所有物品 0 1 2 3 4
Goods allGoods[5]= { {20,60,false},{30,120,false},{10,50,false},{20,20,false},{40,100,false} };
//背包重量
int bagWeight = 100;
//物品总数量
int totalNumber = 5;
int bag(int i,int wei) {
int totalPrice=0;
if(i==totalNumber)return 0;
if( allGoods[i].weight>wei ) {
//物理存储空间:就是不能放下
totalPrice= bag(i+1,wei);
} else {
//能放下:出现选择 放还是不放,看收益多少
totalPrice=max(bag(i+1,wei-allGoods[i].weight)+allGoods[i].price , bag(i+1,wei) );
}
return totalPrice;
}
#include
#include
using namespace std;
struct Goods {
//重量
int weight;
//价值
int price;
//物品状态 1 已经使用,0 未使用
int isUse;
};
//0 1 (不可分割,数量有限)
//所有物品 0 1 2 3 4
Goods allGoods[5]= { {20,60,false},{30,120,false},{10,50,false},{20,20,false},{40,100,false} };
//背包重量
int bagWeight = 100;
//物品总数量
int totalNumber = 5;
void showBag() {
for(int i=0; i<5; i++) {
if(allGoods[i].isUse)
cout<=allGoods[idx].weight*i) {
allGoods[idx].isUse=i;
totalPrice+=allGoods[idx].price*i;
if(idx==4) {
if(totalPrice>maxPrice ) {
maxPrice=totalPrice;
showBag();
cout<
#include
#include
using namespace std;
int main(int argc, char** argv) {
//物品信息
int goods[3][3]= { {1,4},{2,3} };
//背包容量
int bagWeight=0;
cout<<"请输入背包容量:"<>bagWeight;
//状态表
int db[4][bagWeight+1]= {0};
for(int i=0; i<4; i++) {
for(int j=0; jwt ) {
//如果背包不能装下物品,保留背包上一次的结果
db[w][wt]=db[w-1][wt];
} else {
//能装下,计算本物品价值和剩余容量的最大价值
int val=goods[w-1][1] + db[w-1][ wt- goods[w-1][0] ];
//背包原来的价值
int val_= db[w-1][wt];
//计算最大值
db[w][wt]=val>val_?val:val_;
}
}
}
for(int i=1; i<3; i++) {
for(int j=1; j<=bagWeight; j++) {
cout<
只看不练假把式,只练不思假学问。