1. 程式人生 > >甜點(多重揹包+二進位制優化)

甜點(多重揹包+二進位制優化)

描述

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