CSUOJ:经营小卖部



Description

      暑假很多店都关门了,还坚持营业的店可以收揽大多数客户。看准了这个商机,你和小伙伴们打算集资开一个小卖部。

      你们总共集资了X元,可以用来购置商品和其他配置。每个商品有自己的进价和售价,你可以根据自己的要求以进价购入任意数量的商品,并全部以售价卖出。可是因为供货商暑期停止供货,所以你们只能使用X元提前买好商品并在暑假卖掉,暑假中不能再进货。此外,部分商品要求小卖部要有对应设施,比如冰淇淋和饮料要求有冰箱,粽子和方便面要求有微波炉。那么,如何才能得到最大利润?

Input

      多组数据,第一行有一个整数T,表示有T组数据(T<=100)。

      以下每组数据第一行有四个整数X,N,P1和P2。X是你们的资金总数(1<=X<=1000),N表示商品种类数(1<=N<=100),P1和P2分别表示冰箱和微波炉的价格(1<=P1,P2<=1000)。之后N行每行三个整数C1,C2(1<=C1,C2<=1000)和A,分别表示这个商品的进价、售价和对设备的要求(A为0表示无需求,A为1表示需要冰箱,A为2表示需要微波炉)。

Output

      一个整数,表示最大的利润。

Sample Input

2
10 3 1 1
1 2 0
1 3 1
2 4 2
10 3 1 1
5 6 0
3 5 1
5 11 2

Sample Output

17
6

分析:卧槽,这么显而易见的背包。分四种情况分别DP,dp0_没有冰箱没有微波炉;dp1_有冰箱没有微波炉;dp2_有微波炉没有冰箱;dp3_冰箱微波炉都有。然后在一个DP的循环里面判断四种情况的可行性,然后剩下的就是很普通的背包啦。。。不过我的方法略笨重,代码80行,700msAC的,我看status里面大家都是100ms以内,暂时还不知道是怎么优化的。

总结:背包还是比较重要的,各种变形各种熟悉又陌生,又爱又恨的。背包还是要多啃一点。


下面是代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<cmath>
using namespace std;
typedef long long LL;
int t,X,N,p1,p2;
int dp3[105][1005];
int dp2[105][1005];
int dp1[105][1005];
int dp0[105][1005];
int C[105];
int W[105];
int P[105];
int main()
{
 //   freopen("in.txt","r",stdin);
    scanf("%d",&t);
    while(t--){
        scanf("%d%d%d%d",&X,&N,&p1,&p2);
        for(int i=1;i<=N;++i){
            scanf("%d%d%d",&C[i],&W[i],&P[i]);
        }
        memset(dp3,0,sizeof(dp3));
        memset(dp2,0,sizeof(dp2));
        memset(dp1,0,sizeof(dp1));
        memset(dp0,0,sizeof(dp0));
        for(int i=1;i<=N;++i){
            for(int j=0;j<=X;++j){
                if(j+p1+p2<=X)dp3[i][j]=dp3[i-1][j];
                if(j+p2<=X)dp2[i][j]=dp2[i-1][j];
                if(j+p1<=X)dp1[i][j]=dp1[i-1][j];
                dp0[i][j]=dp0[i-1][j];
                for(int k=1;k<=i;++k){
                    if(j-C[i]>=0){
                        if(j+p1+p2<=X)dp3[i][j]=max(dp3[i][j],dp3[k][j-C[i]]+W[i]-C[i]);
                    }
                    if(P[i]!=1){
                        if(j-C[i]>=0){
                            if(j+p2<=X)dp2[i][j]=max(dp2[i][j],dp2[k][j-C[i]]+W[i]-C[i]);
                        }
                    }
                    if(P[i]!=2){
                        if(j-C[i]>=0){
                            if(j+p1<=X)dp1[i][j]=max(dp1[i][j],dp1[k][j-C[i]]+W[i]-C[i]);
                        }
                    }
                    if(P[i]!=2&&P[i]!=1){
                        if(j-C[i]>=0)
                            dp0[i][j]=max(dp0[i][j],dp0[k][j-C[i]]+W[i]-C[i]);
                    }
                }
            }
        }int m0,m1,m2,m3;
        m0=0;m1=0;m2=0;m3=0;
        for(int i=1;i<=N;++i){
            for(int j=1;j<=X;++j){
                if(m1<dp1[i][j])
                    m1=dp1[i][j];
                if(m2<dp2[i][j])
                    m2=dp2[i][j];
                if(m3<dp3[i][j])
                    m3=dp3[i][j];
                if(m0<dp0[i][j])
                    m0=dp0[i][j];
            }
        }
      if(m1==0&&m2==0&&m3==0&&m0==0){
        printf("0\n");continue;
      }
      m1-=p1;m2-=p2;m3=m3-p1-p2;//这一步很重要!!!得到的收入还要减去购买设备的钱才是利润!!
        printf("%d\n",max(max(m1,m0),max(m2,m3)));
    }
    return 0;
}
 
/**************************************************************
    Problem: 1006
    Language: C++
    Result: Accepted
    Time:700 ms
    Memory:3188 kb
****************************************************************/



更新更新更新。。。。。。。。。。。。。。。管理员改了数据。。。。。这份代码TLE了。。。。哭

///

再更新。。。今天早上把这道题重新整理思路做了一遍,才想起完全背包的第三层循环不是前i次选择物品时重量为j-C[i],应该是对取k件物品的k循环就好,只需要对上一次的dp进行累加判断。。。。渣渣还是渣渣。

下面是A的代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int C[105];
int W[105];
int P[105];
int dp[105][1005][4];
int t,x,n,p1,p2;

int main()
{
    scanf("%d",&t);
    while(t--){
        scanf("%d%d%d%d",&x,&n,&p1,&p2);
        for(int i=1;i<=n;++i){
            scanf("%d%d%d",&C[i],&W[i],&P[i]);
        }
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;++i){
            for(int j=1;j<=x;++j){
                dp[i][j][0]=dp[i-1][j][0];
                if(j+p1<=x)dp[i][j][1]=dp[i-1][j][1];
                if(j+p2<=x)dp[i][j][2]=dp[i-1][j][2];
                if(j+p1+p2<=x)dp[i][j][3]=dp[i-1][j][3];
                for(int k=1;;++k){
                    if(j-k*C[i]>=0){
                        if(!P[i])
                            dp[i][j][0]=max(dp[i][j][0],dp[i-1][j-k*C[i]][0]+k*(W[i]-C[i]));
                        if(j+p1<=x&&P[i]!=2)
                            dp[i][j][1]=max(dp[i][j][1],dp[i-1][j-k*C[i]][1]+k*(W[i]-C[i]));
                        if(j+p2<=x&&P[i]!=1)
                            dp[i][j][2]=max(dp[i][j][2],dp[i-1][j-k*C[i]][2]+k*(W[i]-C[i]));
                        if(j+p1+p2<=x)
                            dp[i][j][3]=max(dp[i][j][3],dp[i-1][j-k*C[i]][3]+k*(W[i]-C[i]));
                    }else break;
                }
            }
        }
        printf("%d\n",max(max(dp[n][x][0],dp[n][x-p1][1]-p1),max(dp[n][x-p2][2]-p2,dp[n][x-p1-p2][3]-p1-p2)));
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值