题意:有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; }