这道题有着浓浓的背包气氛。所以我们可以这样想:可以把每个优惠方案都当做一个物品,每个单买所需要花的钱也当做一个物品。(也就是代码中的p结构体数组)而且基于此题的环境,这题是一个完全背包。
另外因为本题的算法比较亲民,至多买5种物品,每种物品最多买5个,所以我们可以(开创性地)使用五维背包。
状态:设f[i][j][k][a][b]表示买i件物品1,j件物品2,k件物品3,a件物品4,b件物品5所需要的最小价钱。(也就是说,我们熟悉的背包模板中f[i]中i的含义从体积在此题背景下变成了购买个数)
转移:f[i][j][k][a][b]=min(f[i][j][k][a][b],f[i-p[pos].cnt[1]][j-p[pos].cnt[2]][k-p[pos].cnt[3]][a-p[pos].cnt[4]][b-p[pos].cnt[5]]+p[pos].val);
边界:f[0][0]=0,其余为正无穷。(这种条件有时必要有时不必要,需要 具体分析)
将繁琐的数据输入处理后,我们就开始进行背包了。
但有一点需要注意,也是本题的重难点(之一)。也就是各个物品的编号给他转成1~5.但是其实数据已经约定了,购买方案中涉及到的产品应该也都是要买的。
所以每组数据涉及到的物品也就最多5个。
* 本题其实还可以用最短路做,这也是我之前比较倾向的算法。但是如何把各种购买方案映射好,却是一个难题。所以放弃了==
(@Sarah :每个节点的标号可以映射成一个篮子的物品个数情况,每一个优惠方式(包括以物品原价购买)表示一条边,权值就是花费,所以就是求一个从空篮子到目标篮子的最短路径。)
Code
1 /* 2 ID:cellur_2 3 TASK:shopping 4 LANG:C++ 5 */ 6 #include<cstdio> 7 #include<algorithm> 8 #include<map> 9 10 using namespace std; 11 const int inf=0x3f3f3f3f; 12 13 int s,n,b,t; 14 int real[10]; 15 int f[10][10][10][10][10]; 16 struct goods{ 17 int val; 18 int n; 19 int cnt[10]; 20 }p[200]; 21 map<int,int>m; 22 23 void init() 24 { 25 for(int i=0;i<=5;i++) 26 for(int j=0;j<=5;j++) 27 for(int k=0;k<=5;k++) 28 for(int a=0;a<=5;a++) 29 for(int b=0;b<=5;b++) 30 f[i][j][k][a][b]=inf; 31 f[0][0][0][0][0]=0; 32 } 33 34 int main() 35 { 36 freopen("shopping.in","r",stdin); 37 freopen("shopping.out","w",stdout); 38 scanf("%d",&s); 39 for(int i=1;i<=s;i++) 40 { 41 scanf("%d",&n); 42 p[i].n=n; 43 for(int j=1;j<=n;j++) 44 { 45 int c=0,k=0; 46 scanf("%d%d",&c,&k); 47 if(m[c]==0) t++,m[c]=t; 48 p[i].cnt[m[c]]=k; 49 } 50 scanf("%d",&p[i].val); 51 } 52 scanf("%d",&b); 53 for(int i=1;i<=b;i++) 54 { 55 s++; 56 int a=0,d=0,e=0; 57 scanf("%d%d%d",&a,&d,&e); 58 if(m[a]==0) t++,m[a]=t; 59 p[s].n=1,p[s].val=e,p[s].cnt[m[a]]=1; 60 real[m[a]]=d; 61 } 62 init(); 63 for(int pos=1;pos<=s;pos++) 64 for(int i=p[pos].cnt[1];i<=real[1];i++) 65 for(int j=p[pos].cnt[2];j<=real[2];j++) 66 for(int k=p[pos].cnt[3];k<=real[3];k++) 67 for(int a=p[pos].cnt[4];a<=real[4];a++) 68 for(int b=p[pos].cnt[5];b<=real[5];b++) 69 f[i][j][k][a][b]=min(f[i][j][k][a][b],f[i-p[pos].cnt[1]][j-p[pos].cnt[2]][k-p[pos].cnt[3]][a-p[pos].cnt[4]][b-p[pos].cnt[5]]+p[pos].val); 70 printf("%d ",f[real[1]][real[2]][real[3]][real[4]][real[5]]); 71 return 0; 72 }