HDU 5445 Food Problem
2015-10-07 00:13
330 查看
题意:有n种糖果,m种箱子,需要的能量为p。每种糖果有它的能量、体积、数量,每种箱子有它的容量、价格、数量,问至少获得p能量的前提下,最少花多少钱
思路:首先可以知道这是一个背包,然后可以求出能量为i的时候最小的体积。如果箱子也这么做的话会超时,因为求出的最小的体积会很大,所以背包空间太大。题目中给出最终的金额不超过50000,所以可以求出当前金额能获得的最大体积,这样扫一遍就知道结果了。
多重背包:这里使用了单调队列优化多重背包,优化掉了二进制多重背包的log。
单调队列优化背包:详见:《浅谈几类背包题》
然后说下自己的理解:F[j*v+d]-j*w,对于放进单调队列中的这个key值我开始很不理解-j*w是个什么东西,后来理解了发现很巧妙。
对于每个j,先把现在j对应的体积(j*v+d)放进单调队列,然后再更新dp[j*v+d],实际上就是用i-1的结果来更新i。
对于-j*w,假设当前单调队列在j的时候处理完毕,队列首的元素为j',所以就要用j'的key值更新j,j'和j之间的值其实就是相差(j-j')*w,也就是j*w-j'*w,这两项就是论文中加上和减去的那两项。
//唉,弱逼看了好久才懂T T
代码:
思路:首先可以知道这是一个背包,然后可以求出能量为i的时候最小的体积。如果箱子也这么做的话会超时,因为求出的最小的体积会很大,所以背包空间太大。题目中给出最终的金额不超过50000,所以可以求出当前金额能获得的最大体积,这样扫一遍就知道结果了。
多重背包:这里使用了单调队列优化多重背包,优化掉了二进制多重背包的log。
单调队列优化背包:详见:《浅谈几类背包题》
然后说下自己的理解:F[j*v+d]-j*w,对于放进单调队列中的这个key值我开始很不理解-j*w是个什么东西,后来理解了发现很巧妙。
对于每个j,先把现在j对应的体积(j*v+d)放进单调队列,然后再更新dp[j*v+d],实际上就是用i-1的结果来更新i。
对于-j*w,假设当前单调队列在j的时候处理完毕,队列首的元素为j',所以就要用j'的key值更新j,j'和j之间的值其实就是相差(j-j')*w,也就是j*w-j'*w,这两项就是论文中加上和减去的那两项。
//唉,弱逼看了好久才懂T T
代码:
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> using namespace std; const int inf = 0x3f3f3f3f; struct Node { int val,cost,num; }na[210]; int dp[50500]; struct QQ{ int j,key; }qq[510000]; void mul_bag_min(int n,int C){ memset(dp,inf,sizeof(dp)); dp[0] = 0; for(int i = 0;i < n;i ++){ int val = na[i].val,cost = na[i].cost,num = na[i].num; for(int d = 0;d < val;d ++){ int head = 0,tail = -1; int siz = (C-d)/val; for(int j = 0;j <= siz;j ++){ int vv = j*val+d; int key = dp[vv] - j*cost; while(tail >= head&&qq[tail].key >= key)tail --; qq[++tail] = (QQ){j,key}; while(tail >= head&&qq[head].j + num < j)head ++; dp[vv] = min(dp[vv],qq[head].key + j*cost); //cout<<vv<<' '<<dp[vv]<<endl; } } } } void mul_bag_max(int n,int C){ memset(dp,0,sizeof(dp)); for(int i = 0;i < n;i ++){ int val = na[i].val,cost = na[i].cost,num = na[i].num; for(int d = 0;d < val;d ++){ int head = 0,tail = -1; int siz = (C-d)/val; for(int j = 0;j <= siz;j ++){ int vv = j*val+d; int key = dp[vv] - j*cost; while(tail >= head&&qq[tail].key <= key)tail --; qq[++tail] = (QQ){j,key}; while(tail >= head&&qq[head].j + num < j)head ++; dp[vv] = max(dp[vv],qq[head].key + j*cost); //cout<<vv<<' '<<dp[vv]<<endl; } } } } int main(){ int T; scanf("%d",&T); while(T --){ int n,m,p; scanf("%d%d%d",&n,&m,&p); for(int i = 0;i < n;i ++){ scanf("%d%d%d",&na[i].val,&na[i].cost,&na[i].num); } mul_bag_min(n,p+150); int mina = inf; for(int i = p;i < p+150;i ++){ mina = min(mina,dp[i]); } if(mina == inf){ puts("TAT"); continue; } for(int i = 0;i < m;i ++){ scanf("%d%d%d",&na[i].cost,&na[i].val,&na[i].num); } mul_bag_max(m,50000); int ans = inf; for(int i = 0;i <= 50000;i ++){ if(dp[i] >= mina){ ans = i; break; } } if(ans > 50000)puts("TAT"); else cout<<ans<<endl; } return 0; }
相关文章推荐
- 浅谈单调队列、单调栈
- PHP动态规划解决0-1背包问题实例分析
- PHP贪婪算法解决0-1背包问题实例分析
- PHP回溯法解决0-1背包问题实例分析
- hdu 1203 I NEED A OFFER! 01背包
- sjtu online judge 1034 二哥的金链
- HDU 1203 I NEED A OFFER! 题解
- 多重背包问题的单调队列优化 转载
- [BZOJ1499][NOI2005][DP+优化]瑰丽华尔兹
- 背包问题(贪婪法)
- hdu4193 hoj3107
- HDU3530
- 【分组背包】开心的金明
- 【01背包】原型
- 【bzoj1047】【单调队列】【HAOI2007】理想的正方形
- 2015 Multi-University Training Contest 1 Hdu 5289 Assignment
- HDU 1203 i need a offer
- 小P的故事——神奇的饭卡(0—1背包,求剩余钱最少)
- HDU 1494 跑跑卡丁车
- HDU 2159 DP