目录
算法笔记---DFS--背包装入的最大价值问题P273
深搜
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=30;
int n,V,maxValue;
int w[maxn],c[maxn];
void dfs(int index,int sumW,int sumC){
if(index==n){
if(sumW<=V && sumC>maxValue)
maxValue=sumC;
return;
}
//岔道口
dfs(index+1,sumW,sumC);//不选第index个物品
dfs(index+1,sumW+w[index],sumC+c[index]); //选第index件物品
}
int main(){
scanf("%d%d",&n,&V);
for(int i=0;i<n;i++) scanf("%d",&w[i]);
for(int i=0;i<n;i++) scanf("%d",&c[i]);
dfs(0,0,0);
printf("%d",maxValue);
return 0;
}
运行结果:
(未采用剪枝策略的深度优先搜索)存在以下主要缺点:
无用搜索: 代码没有实施任何剪枝策略,这意味着在递归过程中,即使后续选择可能导致总重量超过背包容量,程序仍然会尝试选择当前物品并继续进行递归。这导致了大量的无用搜索,即探索了许多不可能构成有效解的状态(即总重量超过背包容量的物品组合),浪费了计算资源。
效率低下: 由于缺乏剪枝,算法在处理具有大量可行解的问题实例时,尤其是当物品数量较大或背包容量相对较小时,会面临非常大的搜索空间。在这种情况下,算法的时间复杂度可能是指数级别的,即随着物品数量的增长,所需计算时间呈爆炸性增长,导致算法在实际应用中可能无法在合理时间内找到解。
内存消耗: 深度优先搜索通常伴随着较深的递归栈,特别是在没有剪枝的情况下。当递归层次很深时,可能会耗尽可用的栈空间,导致程序崩溃。虽然这个问题在本例中可能不如时间复杂度问题突出,但对于某些特定的输入数据或在资源有限的环境中,仍然可能成为问题。
代码可读性和可维护性: 旧版代码中的“岔道口”注释说明了两种选择(选或不选当前物品)的递归调用,但代码结构并未清晰地反映出这两种选择的逻辑关系。改进后的版本通过条件判断和嵌套结构,使代码逻辑更为直观,增强了可读性和可维护性。
总结而言,旧版本代码的主要缺点在于未利用剪枝策略来避免无用搜索,导致算法效率低下,内存消耗可能较大,并且代码结构不够清晰。这些问题在改进后的版本中得到了有效改善。
改进
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=30;
int n,V,maxValue;
int w[maxn],c[maxn];
//void dfs(int index,int sumW,int sumC){
// if(index==n){
// if(sumW<=V && sumC>maxValue)
// maxValue=sumC;
// return;
// }
//
// //岔道口
// dfs(index+1,sumW,sumC);//不选第index个物品
// dfs(index+1,sumW+w[index],sumC+c[index]); //选第index件物品
//}
// 改进优化---剪枝
void dfs(int index,int sumW,int sumC){
if(index==n) return;
dfs(index+1,sumW,sumC); //不选
if(sumW+w[index]<=V){
//更新最大价值
if(sumC+c[index]>maxValue) maxValue=sumC+c[index];
dfs(index+1,sumW+w[index],sumC+c[index]); //选
}
}
int main(){
scanf("%d%d",&n,&V);
for(int i=0;i<n;i++) scanf("%d",&w[i]);
for(int i=0;i<n;i++) scanf("%d",&c[i]);
dfs(0,0,0);
printf("%d",maxValue);
return 0;
}
新版本代码对原始的深度优先搜索(DFS)算法进行了优化,引入了剪枝策略。这种改进的好处体现在以下几个方面:
减少无用搜索: 原始版本的DFS在递归过程中,即使后续选择可能导致总重量超过背包容量,也会尝试选择当前物品。而在改进版本中,添加了条件判断
if(sumW+w[index]<=V)
,只有当选择当前物品后总重量仍不超过背包容量时,才继续进行递归搜索。这样,对于那些会导致总重量超限的选择,程序会提前终止这部分递归路径,避免了不必要的计算,大大减少了无用搜索空间。提高效率: 通过剪枝,程序减少了无效递归调用次数,从而降低了时间复杂度。对于背包问题这类NP完全问题,尽管深度优先搜索无法保证在最坏情况下达到最优解的时间复杂度,但合理的剪枝策略可以显著提升实际运行效率,尤其是在问题规模较大或数据分布有利于剪枝时。
简化逻辑: 改进后的代码结构更为简洁,将“不选”和“选”两种情况合并到了同一个递归函数中。在满足重量约束的前提下,先更新最大价值(若有),然后才进行“选”的递归调用。这样的处理方式使得代码逻辑更加紧凑,易于理解与维护。
总结来说,改进后的写法通过剪枝策略有效地减少了无用搜索,提高了算法效率,同时简化了代码结构。这对于处理背包问题等需要大量搜索的场景具有明显优势。