01背包问题

来源:互联网 发布:seo零基础 编辑:程序博客网 时间:2024/06/01 17:17
首先我们来回顾一下DAG的有向无环图
硬币问题就是确定起点还有终点的DAG 最大 问题(其实有最小问题的 因为有起点和终点)
题目意思就是在面值确定的情况下,有N种无数的硬币 问你最大 最少使用多少硬币
现在说一下01背包问题吧 就是说在不超过体积为C的情况下 有N种无数个背包 每一种背包都是有自己的体积(这里就是相当于硬币面值),然后有自己的重量
问你最大能背多少重量
这里就是有确定的起点(C)但是没有确定的终点(因为不一定能全部用完吧)
硬币问题时候求个数就是相当于 边的权值为1 
背包问题求的是重量就是边的权值为重量  那么加一变为+W[i]就可以了






但是真正的01背包问题是没有无限个背包那么多的 往往每一个背包只有一个


因为现在每种背包只有一种嘛 如果还是之前的方法的话你是没有办法知道现在状态
到底用了哪些背包 还有到底有没有使用重复的背包 


其实我刚刚想了一下可以使用二位数组来表达(姿势增加了 美滋滋)
D[I]][J]
I是代表计算到第几个背包这样就保证了每一个背包只是用了两种状态以及这种背包是考虑到了里面了
J是代表当占有J体积的时候 
D数组的值是代表当前状态最好的决定


讲到这里我突然想到了动态规划的内容 当前状态是之前状态的总结吧 前面的状态是无法直接影响到后面的状态
并且也是符合最优子结构原理


首先初始化二维数组为0 然后的d[i][j]=max(d[i+1][j],d[i+1][j-v[i]]+W[i])
i是代表第i个背包 并且保证j-v[i]>0 ,不然就是直接赋值为d[i+1][j]


其实讲到这里你有没有发现一个很有趣的情况,我现在先举个例子吧
a,b,c,d,e,f,G
a,b,c,d,e,f,g
再计算第i行时候 我先把第i+1行的值全部复制上去先 然后你会发现当你计算G时候 你所用到的值永远是在你计算的值后面或者是不存在的
综上所诉 这个可以转换为一维数组 但是这个数组初始话为0 然后每一次都是从后面往前面计算的


代码实现吧
其实可以输入一个背包就处理一次的
memset(f,0,sizeof(f));
for(int i=0;i<n;i++)
{
scanf("%d",&V,&W);
for(int j=C;j>=0;j--)
  {
if(j>V) f[j]=max(f[j],f[j-V]+W);
  }
}
原创粉丝点击