描述
小z准备举办一个比赛。他需要提供一些甜点给参赛者来补充能量。每种甜品有一定的能量ti和大小ui,且每种甜点最多有vi个。
小z准备用箱子来包装甜点。箱子可以容纳一定体积的甜点且需要一定的费用。小z有一种魔法,可以将一个甜点分成多份装在箱子里,最后再合在一起(但合成之后必须是完整的一个)。
小z想知道准备能量至少为P的甜点的最小大小和最少需要多少费用来购买箱子,如果最少费用超过小z所拥有的钱数k则输出FAIL。
输入
第一行为4个正整数n,m,p, k( 1 ≤ n ≤ 200,1 ≤ m ≤ 200,0 ≤ p ≤ 50000, k <= 50000)分别代表甜点种类,箱子种类和参赛者比赛所需要补充的能量和小z所拥有的钱数。 接下来的n行,每行包含3个整数ti, ui, vi ( 1 ≤ ti ≤ 100,1 ≤ ui ≤ 100,1 ≤ vi ≤ 100) , 代表第i类甜点可以提供ti的能量,它的大小为ui并且小明最多有vi个该种类的甜点。 接下来又有m行,每一行包含3个整数xi, yi, zi ( 1 ≤ xj ≤ 100,1 ≤ yj ≤ 100,1 ≤ zj ≤ 100), 代表第i类箱子可以容纳xi大小的甜点,该类箱子的单价yi,并且小z最多可以使用zi个该类的箱子。
输出
第一行请输出最小的甜点大小。 第二行请输出最小的箱子费用,并且费用不能超过k。否则,输出FAIL。
样例输入1
5 3 34 34 1 4 1 9 4 2 5 3 3 1 3 3 5 3 2 3 4 5 6 7 5 5 3 8
样例输出1
19 12
思路:我一直觉得这题有毒,比赛的时候再想那句“小z有一种魔法,可以将一个甜点分成多份装在箱子里,最后再合在一起(但合成之后必须是完整的一个)。”,到底是什么意思??,因为多重背包来做的话,选择放或不放,可能不能将包装满,但是它说可以把甜点拆分,那我觉得还背包啥啊,第一步选最小体积背包做,第二步贪心做就行。结果......
后来我想明白了,它加那句话就是让你第二步也强行使用背包,因为这样不需要考虑一开始选了什么大小的甜品,直接考虑总重量就行。(但感觉题目还是有点问题,大概是我太菜了)
所以:第一步,求最小体积,逆向来做,设dp[i]表示体积为i的甜品,总能量最大。求完以后,从1到maxn遍历一下,大于P就挑出即可。设为ans1.
第二步:求最小费用,dp2[i]表示费用为i时,获得的最大体积,同样的从1到k遍历一遍,找到dp2[i]>ans1即可退出。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+7;
int n,m,p,k;
int t[maxn],u[maxn],numv[maxn];
int vt[maxn],vu[maxn];
int vx[maxn],vy[maxn],vz[maxn];
int dp[maxn];
struct Point
{
int x,y,z;
}pp[maxn];
bool cmp(Point a,Point b)
{
return a.y*b.x<a.x*b.y;
}
bool vis[500];
int dp2[maxn];
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
scanf("%d%d%d%d",&n,&m,&p,&k);
int cnt=1;
for(int i=1;i<=n;i++)
{
scanf("%d%d%d",&t[i],&u[i],&numv[i]);
for(int j=1;j<=numv[i];j*=2)
{
vt[cnt]=t[i]*j;
vu[cnt++]=u[i]*j;
numv[i]-=j;
}
if(numv[i])
{
vt[cnt]=t[i]*numv[i];
vu[cnt++]=u[i]*numv[i];
}
}
//memset(dp,127,sizeof(dp));
dp[0]=0;
for(int i=1;i<cnt;i++)
{
for(int j=100000;j>=vu[i];j--)
{
dp[j]=max(dp[j],dp[j-vu[i]]+vt[i]);
}
}
cnt=1;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&pp[i].x,&pp[i].y,&pp[i].z);
for(int j=1;j<=pp[i].z;j*=2)
{
vx[cnt]=pp[i].x*j;
vy[cnt++]=pp[i].y*j;
pp[i].z-=j;
}
if(pp[i].z>0)
{
vx[cnt]=pp[i].x*pp[i].z;
vy[cnt++]=pp[i].y*pp[i].z;
}
}
dp2[0]=0;
for(int i=1;i<cnt;i++)
{
for(int j=100000;j>=vy[i];j--)
{
dp2[j]=max(dp2[j],dp2[j-vy[i]]+vx[i]);
}
}
//printf("%d\n",dp2[12]);
int ans1=-1,ans2=-1;
for(int i=1;i<=100000;i++)
{
if(dp[i]>=p)
{
ans1=i;
break;
}
}
if(dp[k]<ans1)
{
printf("FAIL\n");
}
else
{
printf("%d\n",ans1);
for(int i=1;i<=k;i++)
{
if(dp2[i]>=ans1)
{
ans2=i;
break;
}
}
printf("%d\n",ans2);
}
return 0;
}