甜點(多重揹包+二進位制優化)
描述
小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; }