Educational Codeforces Round 21 E. Selling Souvenirs(背包)

题目:http://codeforces.com/contest/808/problem/E

题目大意:
有n个物品,背包容量为m。
每个物品只会有1,2,3个单位占有空间,价值为c。
现在问如何可以使拿到的物品的价值最大。

思路:

主要就是只有三种单位。这就简单了。
贪心的思想,在相同的占有空间的时候,一定选价值最大的。
所以给物品排一个序。
dp第1,2种单位的占有空间,每次可以通过dp[i - 1].s1和dp[i - 2].s2来知道当前已经用到了第多少个第1,2种单位的物品。
然后所有都dp完之后,第三种物品尽可能的选,看看什么情况价值最大就可以了。
那么dp的时候可不可以三种物品都用dp选呢?
答案是不行的
比如 数据
5 7
1 8
2 13
2 13
3 20
3 14
如果我们用dp直接选三种物品的话 就会出现42
正确答案是46
这是因为dp【4】得到的是28而非26 但是这样就把体积为3 的 最大值用了

#include <bits/stdc++.h>
#define ll long long
#define pb push_back
#define inf 0x3f3f3f3f
using namespace std;
const int N=3e5+100;
ll arr[N];
ll s[4][N];
ll num[N];
ll sum[4][N];
struct node
{
    ll v1,v2;
    ll value;
}dp[N];//dp[i].value表示容量到i时所能装的最大价值
bool cmp(ll a,ll b)
{
    return a>b;
}
int main()
{
    //freopen("D://rush.txt","r",stdin);
    ios::sync_with_stdio(false);
    ll n,m,a,b;
    cin>>n>>m;
    for(int i=0;i<n;i++)
    {
        cin>>a>>b;
        s[a][++num[a]]=b;
    }
    for(int i=1;i<=3;i++)
    {
        sort(s[i]+1,s[i]+1+num[i],cmp);
        for(int j=1;j<=num[i];j++)
        {
            sum[i][j]=sum[i][j-1]+s[i][j];
        }
    }
    dp[0].v1=0,dp[0].v2=0,dp[0].value=0;
    ll mx=0;
    for(int i=0;i<=m;i++)
    {
        dp[i]=dp[i-1];
        if(i>=1&&dp[i-1].v1<num[1]&&sum[1][dp[i-1].v1+1]+sum[2][dp[i-1].v2]>dp[i].value)
        {
            dp[i].value =sum[1][dp[i-1].v1+1]+sum[2][dp[i-1].v2];
            dp[i].v1=dp[i-1].v1+1;
            dp[i].v2=dp[i-1].v2;
        }
        if(i>=2&&dp[i-2].v2<num[2]&&sum[1][dp[i-2].v1]+sum[2][dp[i-2].v2+1]>dp[i].value)
        {
            dp[i].value =sum[1][dp[i-2].v1]+sum[2][dp[i-2].v2+1];
            dp[i].v1=dp[i-2].v1;
            dp[i].v2=dp[i-2].v2+1;
        }
        //if(i==4) cout<<dp[4].value;

    }
            for(int j=0;j<=num[3];j++)//为了避免超时把这个循环放外面即可,但需要上面的dp[i]=dp[i-1]
    {
        if(j*3>m) break;
        mx=max(mx,dp[m-j*3].value+sum[3][j]);
    }
    cout<<mx<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ffgcc/article/details/81054212