1.背包问题切入dfs,深度优先,递归找出所有路径(拿法),最终取最大的那个
有n件物品,每种物品的重量为w[i],价值为c[i].现在需要选出若干件物品放入一个容量为V的背包中,使得在选入背包的物品重量和不超过容量V的前提下,让背包中物品的价值之和最大,求最大价值。(1<=n<=20)
2.由上可知,深度优先搜索是一种枚举完所有完整路径以遍历所有情况的搜索方法。给定一个序列,枚举这个序列的所有子序列(可以不连续),然后选择一个“最优”子序列,使得它的某个特征是所有序列中最优的。
eg:给定一个序列,枚举这个序列的所有子序列(可以不连续)
剪枝,如上面容量<=v)
2.1对于上述写法,其实很不安全,虽然数组看起来是个局部变量,但是传递的数组名是个指针,每次操作的都是同一段内存,很危险,如,将选第index个放到不选前面就会影响下面不选时候的判断,此处的标尺实际上是nowK,选时的nowK++对下面明显有影响。
#include<iostream> using namespace std; const int N=3; int a[N]={1,2,3}; //index当前数序号 nowK当前已选数 b[]当前已选数数组 void dfs(int index,int nowK,int b[]){ if(index==N){ if(nowK!=0){ for(int i=0;i<nowK;i++){ cout<<b[i]<<" "; } }else{ cout<<"空集"; } cout<<endl; return; } //顺序调换 //选第index个 b[nowK++]=a[index]; dfs(index+1,nowK,b);//每次b表示的始址都相同,但是每次都会根据nowK及赋值操作更新那段地址的值 //不选第index个 dfs(index+1,nowK,b); } int main(){ int b[N];//已选的数存到b里 dfs(0,0,b);//第0个开始遍历 // cout<<"\n最终的数组b:\n";//证明传递数组名是地址操作 // cout<<b[0]<<" "<<b[1]<<" "<<b[2]<<endl; return 0; }
如何修改,其实很简单,选第n个的情况结束后,将再第n个从数组中删除就是咯,此处表现为nowK--,也即加一行
代码:nowK--;即可#include<iostream> using namespace std; const int N=3; int a[N]={1,2,3}; //index当前数序号 nowK当前已选数 b[]当前已选数数组 void dfs(int index,int nowK,int b[]){ if(index==N){ if(nowK!=0){ for(int i=0;i<nowK;i++){ cout<<b[i]<<" "; } }else{ cout<<"空集"; } cout<<endl; return; } //选第index个 b[nowK++]=a[index]; dfs(index+1,nowK,b);//每次b表示的始址都相同,但是每次都会根据nowK及赋值操作更新那段地址的值 nowK--; //不选第index个 dfs(index+1,nowK,b); } int main(){ int b[N];//已选的数存到b里 dfs(0,0,b);//第0个开始遍历 // cout<<"\n最终的数组b:\n";//证明传递数组名是地址操作 // cout<<b[0]<<" "<<b[1]<<" "<<b[2]<<endl; return 0; }
-----------------------------------------------------------------------------------------------------------------
其实这种不定长数组最好的写法当然还是专业的vector了,
专业写法
3.经典例题
给定N个整数(可能有负数),从中选择K个数,使得这K个数之和恰好等于一个给定的整数X;如果有多种方案,选择
他们中元素平方和最大的一个。数据保证这样的方案唯一。
注意代码中★处的解析
STL高级写法
扩展:若每个数可以重复选多次呢?其他条件不变,只需要将代码该一点点点就行了,选择第index的时候将index+1改成index即可。此外本次将判断改成了前置判断,题目千变万化,边界何时return,觉得还是得靠自己细心(第n-1个尚未判断最优或合法时,绝对不可以直接在第一行if(index==n) return;了)
STL高级写法: