USACO Section 3.3 Shopping Offers - 多重背包_oo

    

    看题目所给的数据范围...最多5种物品..每个物品最多拿5个..那么实际上总状态数最多也就6^5=7776种..并且每种状态可以表示成一个5位的6进制数..每种优惠方案也可以表示成一个5位的6进制数...想到了这里题目就简单了..由于优惠方案是可以多次使用的...所以做一次多重背包可以搞定...我为了方便..就把每个状态都转化成了十进制数...这样感觉更加直观和方便...

/*  
ID: zzyzzy12
LANG: C++
TASK: shopping
*/
#include<iostream>
#include<istream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stack>
#include<algorithm>
#include<queue>
#define oo 1000000000
#define ll long long
using namespace std;
struct node
{
int num,a[6][6],p;
}s[105];
struct node1
{
int p,k;
}products[5];
int n,m,dp[80000],t[1005],goal,_6jie[6];
void make_dp()
{
int h[5],i,j,y,x,temp;
memset(dp,0x7f,sizeof(dp));
if (!m) { dp[goal]=0; return; }
for (i=1;i<=goal;i++)
{
y=0; x=i;
for (j=0;j<5;j++)
{
temp=x%6;
if (temp>products[j].k) goto A;
y+=temp*products[j].p;
x/=6;
}
dp[i]=y;
A: ;
}
for (i=1;i<=n;i++)
{
temp=0;
for (j=1;j<=s[i].num;j++) temp+=_6jie[t[s[i].a[j][0]]]*s[i].a[j][1];
if (dp[temp]>s[i].p) dp[temp]=s[i].p;
for (j=1;j<=goal-temp;j++)
if (dp[j+temp]-dp[j]>s[i].p)
dp[j+temp]=dp[j]+s[i].p;
}
}
int main()
{
freopen("shopping.in","r",stdin);
freopen("shopping.out","w",stdout);
memset(products,0,sizeof(products));
scanf("%d",&n);
int i,j;
for (i=1;i<=n;i++)
{
scanf("%d",&s[i].num);
for (j=1;j<=s[i].num;j++) scanf("%d%d",&s[i].a[j][0],&s[i].a[j][1]);
scanf("%d",&s[i].p);
}
_6jie[0]=1;
for (i=1;i<6;i++) _6jie[i]=6*_6jie[i-1];
goal=0;
scanf("%d",&m);
for (i=0;i<m;i++)
{
scanf("%d",&j);
t[j]=i;
scanf("%d%d",&products[i].k,&products[i].p);
goal+=_6jie[i]*products[i].k;
}
make_dp();
printf("%d\n",dp[goal]);
return 0;
}