算法笔记-动态规划求解0/1背包问题
作者:星河滚烫兮
前言
动态规划作为一种重要思想,被应用于方方面面,其最重要的是动态规划数组(dp数组)和状态转移方程。其实本质上是一种存储过去与当前的状态,同时在状态转移过程中进行最优化,得到全局最优解。以下是解决0/1背包问题的代码,问题描述与求解过程都放在注释里,大家结合代码和注释学习。
C版本
/*
问题描述:已知有背包最大容量为11,现有4个物品:
wi = {2, 3, 4, 6}
vi = {3, 4, 5, 2}
求装入背包的最大价值。
*/
#include<stdio.h>
#define N 4 //物品个数
#define M 11 //背包最大容量
int dp[N+1][M+1]; //动态规划数组:当背包当前容量为M时,决策第i个物品(放或不放)所能达到的最优解(当前背包最大价值)
int wi[] = {0, 2, 3, 4, 6}; //物品重量(0只是为了方便表示i-1防止数组越界)
int vi[] = {0, 3, 4, 5, 2}; //物品价值
int si[] = {0, 0, 0, 0, 0}; //物品状态:放or不放
void StataTransfer(int w[], int v[]) //状态转移函数:构建填充bp数组
{
for(int i=1;i<=N;i++) //i代表对第i个物品进行决策
for(int j=0;j<=M;j++) //j代表对于当前背包容量决策后的最优解
{
if(w[i]>j)
dp[i][j] = dp[i-1][j];
else
//当前状态的最优解=max(放,不放),放是基于上一次背包容量放的(硬放,为了消除最优化因素影响)
dp[i][j] = (dp[i-1][j-w[i]]+v[i]>dp[i-1][j]?dp[i-1][j-w[i]]+v[i]:dp[i-1][j]);
}
}
void Traceback(void) //由dp数组动态规划表回溯得到状态
{
int temp = M;
for(int i=N;i>0;i--)
{
if(dp[i][temp]==dp[i-1][temp])
si[i] = 0;
else
{
si[i] = 1;
temp = temp-wi[i];
}
}
}
void dpDisplay(void)
{
printf("\n动态规划数组dp如下:\ni/j| ");
for(int z=0;z<=M;z++)
printf("%d ",z);
printf("\n");
for(int i=1;i<=N;i++)
{
printf(" %d | ",i);
for(int j=0;j<=M;j++)
printf("%d ",dp[i][j]);
printf("\n");
}
}
void stateDisplay(void)
{
printf("\n状态数组si如下:\nsi[]={");
for(int i=1;i<=N;i++)
printf("%d ",si[i]);
printf("\b}\n");
}
int main()
{
StataTransfer(wi, vi);
dpDisplay();
Traceback();
stateDisplay();
}