codeforcodeforces 808E——Selling Souvenirs(动态规划)官方题解详解
来源:互联网 发布:cad2014软件多少钱 编辑:程序博客网 时间:2024/06/07 20:02
之前写得贪心是有问题的。
贪心的策略并不行,只是能过测试点而已。
因为如果你的体积刚好只能放n个体积为3的,然后有一个体积为1的,性价比高于这些体积为三的,但是价值要低一些,那么贪心的策略会选择体积为1的。总价值会低一些。
看了官方题解之后会写正解了,详细说一下。先贴一下原文。
There are lots of different solutions for this problem.
We can iterate on the number of 3-elements we will take (in this editorial k-element is a souvenir with weight k). When fixing the number of 3-elements (let it be x), we want to know the best possible answer for the weight m - 3x, while taking into account only 1-elements and 2-elements.
To answer these queries, we can precalculate the values dp[w] — triples (cost, cnt1, cnt2), where cost is the best possible answer for the weight w, and cnt1 and cnt2 is the number of 1-elements and 2-elements we are taking to get this answer. Of course, dp[0] = (0, 0, 0), and we can update dp[i + 1] and dp[i + 2] using value of dp[i]. After precalculating dp[w] for each possible w we can iterate on the number of 3-elements.
There are also several binary/ternary search solutions.
首先很容易观察到的是,对于相同质量的物品,我肯定会先选择价值更大的物品。
然后考虑这样一个问题,我们需要选择几个价值为3的物品?如果我选择了x个重量为3的物品,那么总价值就是前x个重量3的物品的价值和,加上重量不超过m-3*x的重量为1和2组成的物品的价值的最大值。
所以用动态规划预处理一下,我只选重量为1和2的物品,质量小于w时的质量最大值。
dp[w]表示一个三元组,表示了重量为w的情况下,最大的价值,以及重量为1和2分别选择的数量。dp[w]可以通过dp[w-1]和dp[w-2]处理出来。
具体可以看代码,感觉逻辑还是比较清楚地。
#include <iostream>#include <cstdio>#include <algorithm>#include <cmath>#include <cstring>#include <string>#include <vector>#include <map>#include <set>using namespace std;#define _ sync_with_stdio(false)const int MAXN=300000+10;const int INF=0x7fffffff;typedef long long ll;struct{ ll v; ll s1,s2;}dp[MAXN];ll a[4][MAXN];//每种数量物品的价值ll s[4][MAXN];//价值前缀和int num[4];//每种重量物品的数量int cmp(int x,int y){return x>y;}int main() { int n,m; scanf("%d%d",&n,&m); num[1]=num[2]=num[3]=0; for(int i=1;i<=n;i++){ ll w,c; scanf("%lld%lld",&w,&c); a[w][++num[w]]=c; } for(int i=1;i<=3;i++){ sort(a[i]+1,a[i]+num[i]+1,cmp); for(int j=1;j<=num[i];j++){ s[i][j]=s[i][j-1]+a[i][j]; } } dp[0].v=dp[0].s1=dp[0].s2=0; for(int i=1;i<=m;i++){ dp[i]=dp[i-1]; if(dp[i-1].v+a[1][dp[i-1].s1+1]>dp[i].v){ dp[i].v=dp[i-1].v+a[1][dp[i-1].s1+1]; dp[i].s1=dp[i-1].s1+1; dp[i].s2=dp[i-1].s2; } if(i>=2&&dp[i-2].v+a[2][dp[i-2].s2+1]>dp[i].v){ dp[i].v=dp[i-2].v+a[2][dp[i-2].s2+1]; dp[i].s1=dp[i-2].s1; dp[i].s2=dp[i-2].s2+1; } } ll res=0; for(int i=0;i<=num[3];i++){ if(m>=i*3) res=max(res,s[3][i]+dp[m-3*i].v); } printf("%I64d\n",res);}
下面这个是错误的解,可以直接忽略。
看起来就像是一个01背包,不过每个物品的体积只有1,2,3三种情况,但是总体积可能很大。
那么就先根据性价比排个序,贪心地缩小体积的范围。然后再用01背包求解。那个范围可以使1000,或者100,或者50都行,最小是多少得看数据...
#include <iostream>#include <cstdio>#include <algorithm>#include <cmath>#include <cstring>#include <string>#include <vector>#include <map>#include <set>#include <iomanip>using namespace std;#define _ ios::sync_with_stdio(false)const int MAXN = 100010;const int INF=0x7fffffff;int n,m;struct node{long long w,c;long long x;}a[MAXN];int cmp(node p,node q){return p.c>q.c;}long long res=0;long long f[MAXN];int main(){scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){scanf("%lld%lld",&a[i].w,&a[i].x);a[i].c=6*a[i].x/a[i].w;}sort(a+1,a+n+1,cmp);int i=1;while(m>1000&&i<=n){res+=a[i].x;m-=a[i].w;i++;}while(i<=n){for(int v=m;v>=a[i].w;v--){f[v]=max(f[v],f[v-a[i].w]+a[i].x);}i++;}printf("%lld\n",res+f[m]);}
额...这个代码有问题,贪心的策略好像并不行,只是能过测试点而已。
因为如果你的体积刚好只能放n个体积为3的,然后有一个体积为1的,性价比高于这些体积为三的,但是价值要低一些,那么贪心的策略会选择体积为1的。总价值会低一些。
- codeforcodeforces 808E——Selling Souvenirs(动态规划)官方题解详解
- 【codeforces 808E】【Selling Souvenirs】【贪心】【动态规划】
- Codeforces 808E Selling Souvenirs 题解
- 808E. Selling Souvenirs***
- CF 808E. Selling Souvenirs
- Codeforces 808E Selling Souvenirs【思维+Dp】
- [杂题 贪心] Codeforces 808E. Selling Souvenirs
- E. Selling Souvenirs
- codeforces Round 21 808E. Selling Souvenirs 【dp好题】
- CodeForces 808E Selling Souvenirs(三分法/单调优化dp)
- Codeforces 808E Selling Souvenirs(花费是倍数关系的背包)
- 01背包 Educational Codeforces Round 21 E. Selling Souvenirs
- Educational Codeforces Round 21 E. Selling Souvenirs 三分, 贪心
- 动态规划—Problem E
- codeforcodeforces 808D——Array Division(查找,set)
- 【动态规划12】codeforces813D Two Melodies(官方题解翻译)
- 动态规划—— E. The Values You Can Make
- 【题解】codeforces765F Souvenirs
- 进程调度模拟算法
- CentOS7 安装JDK1.8
- 设置内外网同时用
- 解决ListView复用的乱码问题
- Video Introduction to Bayesian Data Analysis, Part 1: What is Bayes?
- codeforcodeforces 808E——Selling Souvenirs(动态规划)官方题解详解
- 【ssm个人博客项目实战08】博客的分页显示以及模糊查询,删除。
- 如何传输文件到Linux服务器上
- 字符串中单词的逆转
- Educational Codeforces Round 21 808A Lucky Year
- hook钩子的使用
- install pstricks into texlive
- 剑指offer 8. 旋转数组的最小数字
- 21.输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判