动态规划之 0-1背包问题

C语言写法

C语言自定义函数声明:

  1. 先在全局声明:
    在这里插入图片描述

  2. 把自定义函数写在main函数(入口函数)前面:

int Sort(int A[], int low,int high){ 
    return 0; 
}
int QuickSort(int A[],int low,int high){
	return 0;
}
//. 主函数入口 (写在自定义函数后面)
int main(){
	QuickSort(A, low, high);         //. 调用
	Sort(A, low, high);
}

C语言二维数组的定义:

在这里插入图片描述
例如:
在这里插入图片描述

# include<stdio.h>

int Knapsack01(int V[], int W[],int c, int len);   //.自定义函数声明 

int main(){
	int V[]= {10,3,4,5,4};       //. 物品所占背包容积 
	int W[] = {24,2,9,10,9};     //. 物品的价值 
	int len = sizeof(V)/sizeof(V[0]);   //.一共有几个物品 
//	printf("%d\n",len); 
	Knapsack01(V,W,13,len);          //. 背包的总容积设为13 
} 


int Knapsack01(int V[], int W[],int c, int len){
	int p[len][c];                    //.定义备忘录数组
	int rec[len][c];                  //.定义追踪数组 
	for(int i=0; i<=c; i++)           //.填表,其中第一行和第一列全为0,即 V(i,0)=V(0,j)=0; 
		p[0][i] = 0;                  //.将每一列的第一个初始化为0(也就是第0行) 
	for(int i=0; i<len+1; i++)
		p[i][0] = 0;                //.将每一行的第一个初始化为0(也就是第0列) 
	for(int i=1; i<=len; i++){
		printf("V[%d] = %d\n",i-1,V[i-1]);  //. w与v都是从0开始存的,所以开始i=1时对应0的位置
		for(int j=1; j<=c; j++){
			if(V[i-1]<=j && p[i-1][j-V[i-1]]+W[i-1]>p[i-1][j]){
				p[i][j] = p[i-1][j-V[i-1]]+W[i-1];
				rec[i][j] = 1;
			}//.if
			else{
				p[i][j] = p[i-1][j];
				rec[i][j] = 0;
				printf("p[%d][%d] = %d..   ",i-1,j,p[i-1][j]);
				}//.else
			printf("p[%d][%d] = %d,",i,j,p[i][j]);
		}//.for
		printf("\n");
	}//.for
}

感觉自己写的逻辑上没有问题。。。。但是结果就是有些地方不对
在这里插入图片描述

按理说p[5][13]应该是28(最右下角):
在这里插入图片描述
窒息了。。。。我再肝!肯定是哪里出了问题

Python做法

在这里插入图片描述

1、分析题目

设 f(k ,v)为第 k 件物品,v 为背包剩余容量。那么,这件物品在此刻有两种可能,①.背包装不下。②.背包能装下。其中②又有两种可能,a. 能装下但不装。b.装。
在这里插入图片描述
由此可以得出状态转移方程:
在这里插入图片描述

观察得出每个f(k ,v)与上一次选或不选有关,所以推出备忘录数组(演算的最右下角应该也是8):
在这里插入图片描述
代码如下:

def ZeroOneBag(n, v, b):
    memo = [[0 for i in range(v+1)] for i in range(n+1)]
    MaxCost = 0
    for i in range(1,n+1):    ## 注意:i 代表备忘录数组中的行号,j 代表列号
        for j in range(1,v+1):
            if(j < b[i-1][0]):
                memo[i][j] = memo[i-1][j]
            else:
                memo[i][j] = max(memo[i-1][j], memo[i-1][j-b[i-1][0]]+b[i-1][1])
            MaxCost = max(memo[i][j], MaxCost)
    return MaxCost
    
n, v = map(int,input().split())
b = []
for i in range(n):
    a = list(map(int,input().split()))
    b.append(a)
    
ZeroOneBag(n, v, b)

值得注意的是,代码中的备忘录数组和演算的不同,我没有在代码中做{ f(k ,v),当vk>v时,f(k ,v)= 0 }的判断。
所以,代码得出的备忘录数组为:
在这里插入图片描述
但是,问题不大,编译通过:
在这里插入图片描述

代码还是有点繁琐,备忘录数组可以改进,改进思想为:不需要二维数组,而是一个一维数组,长度为背包容量的大小,每个数值代表该容量所能装下物品的最大值。

def ZeroOneBag(N, V, v, w):
    memo = [0 for i in range(V+1)]  ## 备忘录数组
    for i in range(N):
        for j in range(V,v[i]-1,-1):   ## 从最大容量开始向前循环到当前物品需要的最小容量(比v[i]小的容量再循环下去也没有意义)
            memo[j] = max(memo[j], memo[j-v[i]]+w[i]) ## 更新备忘录数组中当前容量的最大价值
    print(memo[-1])
N, V = map(int,input().split())
v, w = [], []         ## v为容量数组,w为价值数组
for i in range(N):
    a, b = map(int, input().split())
    v.append(a); w.append(b)

ZeroOneBag(N, V, v, w)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值