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;
}