01背包问题:Charm Bracelet (POJ 3624)(外加一个常数的优化)
2013-08-25 10:07
513 查看
Charm Bracelet POJ 3624
就是一道典型的01背包问题:
还有一种方法,使用一个简单的技巧:滚动数组(DP中常用的:优化内存)
1.4初始化的细节问题
我们看到的求最优解的背包问题题目中,事实上有两种不太相同的问法。有的题目要求“恰好装满背包”时的最优解,有的题目则并没有要求必须把背包装满。一种区别这两种问法的实现方法是在初始化的时候有所不同。
如果是第一种问法,要求恰好装满背包,那么在初始化时除了F[0]为0,其它F[1..V]均设为−∞,这样就可以保证最终得到的F[V]是一种恰好装满背包的最优解。
如果并没有要求必须把背包装满,而是只希望价格尽量大,初始化时应该将F[0..V]全部设为0。
这是为什么呢?可以这样理解:初始化的F数组事实上就是在没有任何物品可以放入背包时的合法状态。如果要求背包恰好装满,那么此时只有容量为0的背包可以在什么也不装且价值为0的情况下被“恰好装满”,其它容量的背包均没有合法的解,属于未定义的状态,应该被赋值为-∞了。如果背包并非必须被装满,那么任何容量的背包都有一个合法解“什么都不装”,这个解的价值为0,所以初始时状态的值也就全部为0了。
这个小技巧完全可以推广到其它类型的背包问题,后面不再对进行状态转移之前的初始化进行讲解。(这个理解较易)
1.5一个常数优化
上面伪代码中的
fori←1toN
forv←VtoCi
中第二重循环的下限可以改进。它可以被优化为
fori←1toN
forv←Vtomax(V−ΣNiWi,Ci)
这个优化之所以成立的原因请读者自己思考。(提示:使用二维的转移方程思考较易。)
这个较容易理解:
那个常数优化不错,之可惜他打错了(有点怀疑)
由于只需要最后f[v]的值,倒推前一个物品,其实只要知道f[v-w
]即可。以此类推,对以第j个背包,其实只需要知道到f[v-sum{w[j..n]}]即可,即代码中的
for i=1..N
for v=V..0
可以改成
for i=1..n
bound=max{V-sum{c[i..n]},c[i]}
for v=V..bound
就是一道典型的01背包问题:
#include<iostream> #include<stdio.h> #include<algorithm> #include<string.h> using namespace std; int a[3405],b[3405]; int c[12888]; int main() { int n,m,i,j; while(scanf("%d%d",&n,&m)!=EOF) { for(i=1;i<=n;i++) scanf("%d%d",&a[i],&b[i]); memset(c,0,sizeof(c)); for(i=1;i<=n;i++) for(j=m;j>=a[i];j--) if(c[j]<c[j-a[i]]+b[i]) c[j]=c[j-a[i]]+b[i]; printf("%d\n",c[m]); } return 0; }
还有一种方法,使用一个简单的技巧:滚动数组(DP中常用的:优化内存)
1.4初始化的细节问题
我们看到的求最优解的背包问题题目中,事实上有两种不太相同的问法。有的题目要求“恰好装满背包”时的最优解,有的题目则并没有要求必须把背包装满。一种区别这两种问法的实现方法是在初始化的时候有所不同。
如果是第一种问法,要求恰好装满背包,那么在初始化时除了F[0]为0,其它F[1..V]均设为−∞,这样就可以保证最终得到的F[V]是一种恰好装满背包的最优解。
如果并没有要求必须把背包装满,而是只希望价格尽量大,初始化时应该将F[0..V]全部设为0。
这是为什么呢?可以这样理解:初始化的F数组事实上就是在没有任何物品可以放入背包时的合法状态。如果要求背包恰好装满,那么此时只有容量为0的背包可以在什么也不装且价值为0的情况下被“恰好装满”,其它容量的背包均没有合法的解,属于未定义的状态,应该被赋值为-∞了。如果背包并非必须被装满,那么任何容量的背包都有一个合法解“什么都不装”,这个解的价值为0,所以初始时状态的值也就全部为0了。
这个小技巧完全可以推广到其它类型的背包问题,后面不再对进行状态转移之前的初始化进行讲解。(这个理解较易)
1.5一个常数优化
上面伪代码中的
fori←1toN
forv←VtoCi
中第二重循环的下限可以改进。它可以被优化为
fori←1toN
forv←Vtomax(V−ΣNiWi,Ci)
这个优化之所以成立的原因请读者自己思考。(提示:使用二维的转移方程思考较易。)
这个较容易理解:
那个常数优化不错,之可惜他打错了(有点怀疑)
由于只需要最后f[v]的值,倒推前一个物品,其实只要知道f[v-w
]即可。以此类推,对以第j个背包,其实只需要知道到f[v-sum{w[j..n]}]即可,即代码中的
for i=1..N
for v=V..0
可以改成
for i=1..n
bound=max{V-sum{c[i..n]},c[i]}
for v=V..bound
#include<iostream> #include<stdio.h> #include<algorithm> #include<string.h> using namespace std; int a[3405],b[3405]; int c[12888]; int sum[3405],sb; int main() { int n,m,i,j; while(scanf("%d%d",&n,&m)!=EOF) { for(i=1;i<=n;i++) scanf("%d%d",&a[i],&b[i]); sum =a ; for(i=n-1;i>=1;i--) sum[i]=a[i]+sum[i+1]; memset(c,0,sizeof(c)); for(i=1;i<=n;i++) for(j=m,sb=max(m-sum[i],a[i]);j>=sb;j--) if(c[j]<c[j-a[i]]+b[i]) c[j]=c[j-a[i]]+b[i]; printf("%d\n",c[m]); } return 0; }
相关文章推荐
- [再做01背包] POJ 3624 Charm Bracelet
- POJ3624 - Charm Bracelet - 动态规划之01背包
- POJ 3628 Bookshelf2 / POJ 3624 Charm Bracelet / POJ 1384 初涉01背包与完全背包
- poj 3624 Charm Bracelet DP 0/1 背包问题
- POJ 3624 Charm Bracelet ……(01背包模板题)
- POJ 3624 Charm Bracelet 赤裸裸的0-1背包
- poj-3624-Charm Bracelet0-1背包
- POJ Charm Bracelet 挑饰品 (常规01背包)
- POJ charm bracelet 背包问题的理解
- 简单背包问题——百炼01:Charm Bracelet
- Charm Bracelet poj 01 背包
- POJ 3624 Charm Bracelet (01背包 + 空间优化)
- poj&nbsp;3624&nbsp;Charm&nbsp;Bracelet(0/1背包)
- POJ 3624 Charm Bracelet【裸01背包和关于贪心解 01 背包问题的思考】
- POJ 3624 Charm Bracelet 赤裸裸的0-1背包
- 【0-1背包】-POJ-3624-Charm Bracelet
- poj 3624 Charm Bracelet
- POJ 3624 A - Charm Bracelet
- poj 3624 Charm Bracelet
- poj 3624 Charm Bracelet