给定一个序列,枚举这个序列的所有子序列(子序列中的元素可以不连续,元素不能选择多次).cpp

点击查看代码
/*
第1行给出物品数量n和背包容量V,第2行给出每件物品的重量为w[i],第3行给出每件物品的价值为c[i]。现在需要选出若干件物品放入一个容量为V的背包中,
使得在选入背包的物品重量和不超过V的前提下,让背包中物品的价值之和最大,输出最大价值(1<=n<=20)

这个问题属于常见的DSF问题:给定一个序列,枚举这个序列的所有子序列(子序列中的元素可以不连续,元素不能选择多次)
例如给定序列{1,2,3},所有子序列有{1}、{2}、{3}、{1,2}、{1,3}、{2,3}、{1,2,3}

输入样例:
5 8
3 5 1 2 2
4 5 2 1 3

输出样例2:
10

/*
题目分析:
1、对于每件物品都有2种情况:选择该物品,不选择该物品,相当于深度优先搜索中的递归入口
   当选择的物品数为n,或选择的物品重量和超过V,相当于深度优先搜索中的递归结束条件,即递归出口
2、深度优先搜索函数DFS(index,sumW,sumC)有3个参数:当前指向的第index件物品,背包中的物品总重量和总价值
3、DFS()的递归条件
   (1)不选择第index件物品,问题转换为是否选择第index+1件物品,进递归DFS(index+1, sumW, sumC)
   (2)选择第index件物品,然后进递归DFS(index+1, sumW+w[index], sumC+c[index]),继续判断是否选择第index+1件物品,
   	  注意实参sumW和sumC要加上第index件物品的重量和价值
4、DFS()的递归边界
   (1)当index等于n时,表示扫描完n件物品,如果此时sumW不超过背包重量V,且sumC大于以前记录的背包物品最大价值maxValue,则用sumC更新maxValue数据
*/

#include<cstdio>
#pragma warning(disable:4996) 
const int maxn = 30; //最多20件物品
int n, V, maxValue = 0; //物品件数,背包重量,放入背包的物品的最大价值
int w[maxn], c[maxn]; //每件物品的重量w[i],每件物品的价值c[i]

//index是当前指向的物品号,sumW和sumC是当前背包中的物品总重量和总价值
void DFS(int index, int sumW, int sumC) {
	if (index == n) { //扫描完n件物品
		if (sumW <= V && sumC > maxValue) {	//当前背包中的物品不超过背包容量,且总价值更大
			maxValue = sumC; //则更新最大价值 
		}
		return; //出递归,返回上一层
	}
	DFS(index + 1, sumW, sumC); //不选第index+1件物品
	DFS(index + 1, sumW + w[index], sumC + c[index]); //选择第index+1件物品,然后递归继续选择下一件物品,实参要修改物品总重量和总价值	
}

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); //index初始为0,在DFS()中从第1件物品开始,当前物品总重量和总价值为0
	printf("%d\n", maxValue); //放入背包的物品的最大价值
	return 0;
}

/*
上面代码是把n件物品的选择都确定后才更新最大价值,忽略了背包容量要求不超过V的特点
下面是优化代码:
只有在加入第index件物品后背包容量没超过V,才计算背包中的物品总价值,然后才能判断是否选择第index+1件物品
剪枝:满足某个条件后才能进入下一个递归入口
*/
//index是当前指向的物品号,sumW和sumC是当前背包中的物品总重量和总价值
void DFS(int index, int sumW, int sumC) {
	if (index == n) { //扫描完n件物品
		return; //出递归,返回上一层
	}
	DFS(index + 1, sumW, sumC); //不选第index+1件物品
	if (sumW + w[index] <= V) {	//只有在加入第index件物品后背包容量没超过V
		if (sumC + c[index] > maxValue) { //才计算当前背包中的物品总价值是否大于maxValue
			maxValue = sumC + c[index]; //如果是,则更新最大价值maxValue
		}
	}
	//然后才能选择是否将第index+1件物品加到背包中
	DFS(index + 1, sumW + w[index], sumC + c[index]); //选择第index+1件物品,然后递归继续选择下一件物品,实参要修改物品总重量和总价值	
}

posted @ 2022-09-29 21:22  zhaoo_o  阅读(36)  评论(0)    收藏  举报