codeforcodeforces 808E——Selling Souvenirs(动态规划)官方题解详解

62 篇文章 1 订阅
16 篇文章 0 订阅

E. Selling Souvenirs
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

After several latest reforms many tourists are planning to visit Berland, and Berland people understood that it's an opportunity to earn money and changed their jobs to attract tourists. Petya, for example, left the IT corporation he had been working for and started to sell souvenirs at the market.

This morning, as usual, Petya will come to the market. Petya has n different souvenirs to sell; ith souvenir is characterised by its weight wi and cost ci. Petya knows that he might not be able to carry all the souvenirs to the market. So Petya wants to choose a subset of souvenirs such that its total weight is not greater than m, and total cost is maximum possible.

Help Petya to determine maximum possible total cost.

Input

The first line contains two integers n and m (1 ≤ n ≤ 1000001 ≤ m ≤ 300000) — the number of Petya's souvenirs and total weight that he can carry to the market.

Then n lines follow. ith line contains two integers wi and ci (1 ≤ wi ≤ 31 ≤ ci ≤ 109) — the weight and the cost of ith souvenir.

Output

Print one number — maximum possible total cost of souvenirs that Petya can carry to the market.

Examples
input
1 1
2 1
output
0
input
2 2
1 3
2 2
output
3
input
4 3
3 10
2 7
2 8
1 1
output
10


之前写得贪心是有问题的。

贪心的策略并不行,只是能过测试点而已。

因为如果你的体积刚好只能放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的。总价值会低一些。










  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值