POJ 1170 Shopping Offers

题意:有n(n<=5)种物品,每种个数num<=5,价值1<=val<=999,现在商店推出m(m<=99)种促销方案,即若干种物品放在一起价格会比单个物品的总和便宜,问买到所有物品的最少花多少钱。


分析:六进制状态压缩DP,类似于完全背包。状态作为容量,价格作为价值。


Code:

#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
#include <queue>
#include <cmath>
#include <map>
#include <set>
#define eps 1e-7
#define LL long long
#define pb push_back
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;

const int inf=0x3f3f3f3f;
const int base[6]={1,6,36,216,1296,7776};
struct Offer{
    int st,price;
    Offer(){
        st=price=0;
    }
};
struct Item{
    int cnt,p;
};
int n,m,state;
int Hash[1000],dp[10000];
Offer offer[105];
Item item[5];


bool check(int x,int y){
    for(int i=0;i<n;i++){
        if(x%6+y%6>item[i].cnt) return false;
        x/=6; y/=6;
    }
    return true;
}

int calcu(int s){
    int cost=0;
    for(int i=0;s;i++){
        cost+=(s%6)*item[i].p;
        s/=6;
    }
    return cost;
}

int main()
{
    int code,cnt,p;
    state=0;
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d %d %d",&code,&item[i].cnt,&item[i].p);
        Hash[code]=i;
        state+=base[i]*item[i].cnt;
    }
    scanf("%d",&m);
    for(int i=0;i<m;i++){
        scanf("%d",&p);
        for(int j=0;j<p;j++){
            scanf("%d %d",&code,&cnt);
            offer[i].st+=base[Hash[code]]*cnt;
        }
        scanf("%d",&offer[i].price);
    }
    for(int i=1;i<=state;i++) dp[i]=inf;
    dp[0]=0;
    for(int i=0;i<m;i++){//以M种促销方案作为物品
        for(int j=0;j<=state;j++){//以状态最为容量
            if(dp[j]==inf) continue;
            if(j+offer[i].st<=state&&check(j,offer[i].st)){
                if(dp[j+offer[i].st]>dp[j]+offer[i].price) dp[j+offer[i].st]=dp[j]+offer[i].price;
            }
        }
    }
    int ans=inf,tmp;
    for(int i=0;i<=state;i++){
        tmp=calcu(state-i);
        ans=Min(ans,dp[i]+tmp);
    }
    printf("%d\n",ans);
    return 0;
}


你可能感兴趣的:(POJ 1170 Shopping Offers)