算法设计与分析(期末复习版5.2)

算法设计与分析(期末复习版5.2)

求解0/1背包问题

问题描述:设n个物体编号为1~n,重量用数组w[1…n]表示,价值用数组v[1…n]表示,限制重量用W表示,求解在限制重量约束下,选择那些物体能使物体价值最大

问题分析:选择物体要求体重不超过约束体重W,同时需要满足最大价值,那么我们要设置一个初始变量maxv=0用于后续选择物体之后进行比较交换。这个问题是选择物体,类似于求集合的子集问题,可以将问题的解过程想象成一棵树,将解空间想象成一棵树,定义一个数组x[ i ]来表明是否选择第i个物体,从第一个物体开始作为树的根节点,是否选择,分为两棵子树的根节点,第二层在第一层选择物体与否的基础上是否选择第二个物体,以此类推,直到最后一个物体,即 i(代表索引)指向n为止i。

1.递归框架设计方法

下面我们给出第一中递归框架设计的求解程序代码

#include <stdio.h> // 包含标准输入输出库
#define MAXN 20 // 定义最大物品数量的宏

int n = 4, W = 6; // 定义物品数量和背包容量
int w[] = {0, 5, 3, 2, 1}; // 定义每个物品的重量数组
int v[] = {0, 4, 4, 3, 1}; // 定义每个物品的价值数组
int x[MAXN]; // 定义一个数组来记录每个物品是否被选中
int maxv = 0; // 定义一个变量来记录最大价值,应该定义为全局变量

// 深度优先搜索函数,用于找到最大价值的组合
void dfs(int i, int tw, int tv, int op[]) {
    if (i > n) { // 如果已经检查完所有物品
        if (tw == W && tv > maxv) { // 如果当前总重量等于背包容量且当前价值大于已知的最大价值
            maxv = tv; // 更新最大价值
            for (int j = 1; j <= n; j++) { // 复制当前最优解的选项
                x[j] = op[j]; //op[]数组复制x[]数组,便于后续输出结果 
            }
        }
    } else {
        op[i] = 1; // 选择第i个物品
        dfs(i + 1, tw + w[i], tv + v[i], op); // 递归调用dfs,考虑选择当前物品的情况
        op[i] = 0; // 不选择第i个物品
        dfs(i + 1, tw, tv, op); // 递归调用dfs,考虑不选择当前物品的情况
    }
}

// 打印解决方案的函数
void dispasolution() {
    printf("选择的方案是: ");
    for (int i = 1; i <= n; i++) { // 从1开始循环,因为数组索引从1开始
        if (x[i] == 1) { // 如果第i个物品被选中
            printf("%d ", i); // 打印物品的索引
        }
    }
    printf("\n");
}

// 主函数
int main() {
    int op[MAXN] = {0}; // 初始化决策数组,所有物品初始都不被选择
    dfs(1, 0, 0, op); // 从第一个物品开始dfs搜索
    printf("最大价值为: %d\n", maxv); // 打印出找到的最大价值
    dispasolution(); // 打印出选择的物品方案
    return 0;
}

对左子树进行优化,选择第i个物体放入背包(不超重,超重时左孩子剪枝),相当于在选择之前,进行了一个计算,计算tw+w[i]是否会超过约束条件W=6,如果超过的话不选择第i个物体,直接跳过,进行下一层判断。优化后深度优先遍历核心代码如下:

2.回溯法求解过程

 
void dfs(int i,int tw,int tv,int op[])
{ 
	if(i>n)
	{
		if(tw==W && tv>maxv) 
		  {
		    maxv=tv;
		   for(int j=1;j<=n;j++)
		   x[j]=op[j];
	      }
	}
	else{
	  if(tw+w[i]<=W)
	  {
	  	op[i]=1;
	  	dfs(i+1,tw+w[i],tv+v[i],op);
	  }
	  else 
	  {
	  	op[i]=0;
	  	dfs(i+1,0,0,op);
	   }	 	
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值