概览:可用"搜索"思想来解决的问题一般来说分为两类,一类是像树、图这样有明确数据结构的,这一类理解起来比较直观,搜索过程即一层一层直到最深处;对于隐式图,就没有明确的数据结构,需要根据题意确定状态变化对应的参数,这里先讲后面一种情况。
一、对于没有明确数据结构的深搜
【例题1】有n(1<=n<=20)件物品,每件物品的重量为w[i],价值为v[i]。现在需要选出若干件物品放入一个容量为V的背包中,使得在选入背包的物品重量之和不超过totWeight的前提下,让背包中的物品价值之和最大,求最大价值以及所选物品的编号(假设编号从0开始)。
分析:对于每件物品,都有选或不选两种可能,即dfs的两个分支。深搜过程中要记录当前所选物品的重量之和(记为sumWeight),以及当前物品的价值之和(记为sumValue),当然还有物品的编号idx,由此可基本确定dfs的接口为dfs(int idx, int sumWeight, int sumValue)。假设当前物品编号为idx,若选择该物品,则状态改变为sumWeight+w[idx]和sumValue+v[idx],然后进入下一个物品idx+1;若不选择该物品,则sumWeight和sumValue的状态不变,进入下一个物品idx+1。
输入数据:
5 8 //n件物品 容量V为8
3 5 1 2 4 //每件物品的重量
4 5 2 3 1 //每件物品的价值
输出结果:
10
1 2 3
代码:
#include <cstdio> #include <vector> using namespace std; int w[20],v[20]; vector<int> ans,tmp; int n, totWeight;//物品个数,背包最多可放入放入重量 int maxValue=0; void dfs(int idx,int sumWeight,int sumValue) { if(idx==n) return;//因为下标0~n-1,所以遍历到n时,说明已经遍历完了所有物品 if(sumWeight+w[idx] <= totWeight){//若选择idx号物品不会超过背包最大承受重量,那就选择它 tmp.push_back(idx); if(sumValue+v[idx] > maxValue){ maxValue=sumValue+v[idx]; ans=tmp; } dfs(idx+1,sumWeight+w[idx],sumValue+v[idx]); tmp.pop_back(); } dfs(idx+1,sumWeight,sumValue);//不选择idx号物品 } int main() { scanf("%d%d",&n,&totWeight); for(int i=0;i<n;i++) scanf("%d",&w[i]); for(int i=0;i<n;i++) scanf("%d",&v[i]); dfs(0,0,0); printf("maxValue:%d\n",maxValue); for(int i=0;i<ans.size();i++){ printf("%d ",ans[i]); } return 0; }
【例题2】给出N个整数,从中选出K个数(K<=N,每个数最多只能选一次),使这K个数的和为S,若有多种方案则选择各元素的平方和最大的方案。如给出{2 3 3 4},要求从中选出2个数,使其和为6,则有{2 4}或{3 3},其中{2 4}的平方和更大,则其为最优解。
代码:
#include <cstdio> #include <vector> using namespace std; const int n=4; int data[n]={2,3,3,4}; vector<int> ans,tmp; int k=2,sum=6; int maxSquare=-1; void dfs(int idx,int currK,int currSum,int currSquare) { if(currK==k && currSum==sum){//符合某一条件 if(currSquare>maxSquare){ maxSquare=currSquare; ans=tmp; } return; } if(idx==n || currK>k || currSum>sum) return; tmp.push_back(data[idx]); dfs(idx+1,currK+1,currSum+data[idx],currSquare+data[idx]*data[idx]);//语句1 tmp.pop_back(); dfs(idx+1,currK,currSum,currSquare); } int main() { dfs(0,0,0,0); for(auto it:ans) printf("%d ",it);//输出2,4 return 0; }