概述
题目描述
译自 JOI 2014 Final T2「IOI 饅頭」
有 M 种互不相同的馒头各一个,第 i 个馒头卖 Pi元。
有 N 个包装盒,第 j 个包装盒最多能装 Ci 个馒头,买第 j 个包装盒的花费为 Ej 元。要求只能将一些馒头放进包装盒中打包出售,不能零售,当然也可以不出售某些馒头(卖剩的馒头被出题人吃了,出题人还吃得津津有味~)。售出一盒馒头得到的利润为盒内所有馒头的价格减去包装盒的价格。
现在买下(这 N 个包装盒)其中的一些包装盒(也可以不买,还可以全买),将馒头打包出售,求最大可能利润。
输入格式
第一行两个正整数M,N ,意义如题目描述;
接下来 M 行,每行一个正整数Pi ,表示第 i 个馒头的价格;
接下来 N 行,每行两个正整数Cj,Ej ,表示第 j 个包装盒最多能装 Cj 个馒头,花费 Ej 元。
输出格式
一行一个整数,表示最大可能利润。
样例输入
4 3
180
160
170
190
2 100
3 120
4 250
样例输出
480
样例说明
在本例中,我们选择第一、第二个包装盒,第一个包装盒装第 1,2个馒头,第二个包装盒装第 3,4 个馒头。第一盒馒头的利润是180+160-100=240 元,第二盒馒头的利润是 170+190-120=240 元,因此总利润为 240+240=480元。
思路
贪心+01背包
贪心是把馒头按价值从大到小排序,因为每个馒头的大小是一样的(可以看做1),那么打包的时候肯定是先从价值大的馒头打包
01背包,dp[i][j]表示前i个包装盒装j个馒头的最大利益
代码
#include<bits/stdc++.h>
using namespace std;
int n,m,a[10010],anss,dp[510][10010];
//dp[i][j]表示前i个包装盒装j个馒头的最大利益
struct node{
int c,e;
}b[510];
int cmp(int x,int y) {return x>y;}
int main()
{
scanf("%d%d",&m,&n);
for (int i=1;i<=m;i++) scanf("%d",&a[i]);
sort(a+1,a+1+m,cmp); //一个贪心,很容易想到要将馒头的价值从大到小排序
for (int i=1;i<=m;i++) a[i]+=a[i-1]; //优化,馒头价值的前缀和
for (int i=1;i<=n;i++) scanf("%d%d",&b[i].c,&b[i].e);
for (int i=1;i<=n;i++)//前i个包装盒
for (int j=1;j<=m;j++) //装j个馒头
{
if (j<=b[i].c) dp[i][j]=max(dp[i-1][j],a[j]-b[i].e);
//如果j个馒头可以全部放进去,那么就直接放馒头进去,不用挑来挑去了
//dp[i-1][j]表示不用第i个包装盒,直接继承第i-1个包装盒装j个馒头的利润
//a[j]-b[i].e表示j个馒头全装进去了,还要减去第i个包装盒的费用
else dp[i][j]=max(dp[i-1][j],dp[i-1][j-b[i].c]+a[j]-a[j-b[i].c]-b[i].e);
//dp[i-1][j]表示不用第i个包装盒,直接继承第i-1个包装盒装j个馒头的利润
//dp[i-1][j-b[i].c]表示前面的包装盒装j-b[i].c个馒头的利润,剩下的b[i].c个馒头要留给第i个包装盒装
//a[j]-a[j-b[i].c]表示第i个包装盒要装的 从j开始的前面b[i].c个馒头 的利润
//还要减去b[i].e,也就是第i个包装盒的费用
anss=max(anss,dp[i][j]); //直接在比较后寻找最大值,反正答案总会是dp[i][j]其中的一个
}
cout<<anss<<endl;
return 0;
}
最后
以上就是想人陪短靴为你收集整理的【题解】#2757. 「JOI 2014 Final」IOI 馒头的全部内容,希望文章能够帮你解决【题解】#2757. 「JOI 2014 Final」IOI 馒头所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复