节约空间我自然用了滚动数组…… 偷懒用指针来实现滚动了。
用二进制标志状态。 因为最多只买5种商品。
所以f[][][][][] 每一维空间表示每个商品购买的情况,
这里只说一下二维的情况 f[i][j] = f[a][b] + a[p]
其中: b[p]+a = i c[p] + b = j
说白了,就是用几维空间, 第一维,就是第一个商品的购买数量。 第二维就是第二个商品购买数量……
假如 一个状态 5 3 4 2 1 就是第一个商品买5个,第二个商品买3个,第三个商品买4个,第四个商品买2个,第五个商品买1个。 【所花的最少费用】
那么转移就很明显了…… 直接"套餐"来转移。 为了省事, 把 【只购买一个商品】(也就是输入数据中,最后那几组数据)也列为套餐。
状态压缩呢, 因为题目说了,每个商品最多买5个,所以 用3位二进制来表示一个状态。 最多15个二进制位(这也是很小的)。
优化: 因为5只是100 而不是111. 所以不需要太多的穷举~ 当然我为了省事,我还是一直穷举到111了。
其他嘛,看程序就行了。略有备注。
Executing... Test 1: TEST OK [0.003 secs, 3636 KB] Test 2: TEST OK [0.003 secs, 3636 KB] Test 3: TEST OK [0.003 secs, 3636 KB] Test 4: TEST OK [0.005 secs, 3636 KB] Test 5: TEST OK [0.008 secs, 3636 KB] Test 6: TEST OK [0.003 secs, 3636 KB] Test 7: TEST OK [0.003 secs, 3636 KB] Test 8: TEST OK [0.003 secs, 3636 KB] Test 9: TEST OK [0.005 secs, 3636 KB] Test 10: TEST OK [0.043 secs, 3636 KB] Test 11: TEST OK [0.057 secs, 3636 KB] Test 12: TEST OK [0.035 secs, 3636 KB] All tests OK.
/* TASK:shopping LANG:C++ */ #include <cstdio> #include <cstring> #include <iostream> using namespace std; int kinds, tot_kinds; int f[2][33000]={0}; int *f0 = f[0], *f1= f[1]; int tn[110]; int tk[110][10], tc[110][10], valve[110]; int rel[1000],req[10]; const int ooo[] = {7, 56,448,3584,28672}; void init() { memset(f, 65, sizeof(f)); memset(rel, -1, sizeof(rel)); scanf("%d", &kinds); for (int i = 0; i != kinds; ++ i) { scanf("%d", &tn[i]); //i的优惠方案 要购买的数量 for (int j = 0; j != tn[i]; ++ j) scanf("%d%d", &tc[i][j], &tk[i][j]);//k个编号为c scanf("%d", &valve[i]); //第i套优惠方案的价格 } scanf("%d", &tot_kinds); //需要购买的只有b个产品 int tail = 0; for (int i = 0; i != tot_kinds; ++ i) { int c, k, p; scanf("%d%d%d", &c, &k, &p); // 编号c 要k个,原价是p req[tail] = k; rel[c] = tail++; tn[kinds + i] = 1; tk[kinds + i][0] = 1; tc[kinds + i][0] = c; valve[kinds + i] = p; } } void doit() { memset(f0, 65, sizeof(f)/2); int inf = f0[0], st = 0; f0[0] = 0;//什么都不用的情况下,价格显然为0 for (int i = st; i != kinds + tot_kinds; ++ i) { for (int ci = 0;; ++ ci) { int tmp = 0; for (int j = 0; j != tn[i]; ++ j) { int now = rel[tc[i][j]]; int buy = tk[i][j]; if (buy * ci > req[now]) goto breakfor2; //有不需要的,退出 tmp += (buy * ci) << (now * 3); } for (int j = 0; j != (1 << (tot_kinds * 3)); ++ j) //穷举每个状态,判断是否可以转移,可以转移就转移一下 { if (f0[j] == inf) continue; //如果这个j的状态本来就不存在,肯定不可以转移 //cout<<"j = "<<j<<endl; for (int k = 0; k != tot_kinds; ++ k)// 超出需求,退出,继续下一个循环 if ((tmp & ooo[k]) + (j & ooo[k]) > (req[k] << (k * 3))) goto breakfor3; f1[j + tmp] = min(f0[j] + valve[i] * ci, f1[j + tmp]); breakfor3:; } } breakfor2:; swap(f0, f1); memset(f1, 65, sizeof(f)/2); } int tmp = 0; for (int i = 0; i != tot_kinds; ++ i) tmp += req[i] << (i * 3); printf("%d\n", f0[tmp]); } int main() { freopen("shopping.in","r",stdin); freopen("shopping.out","w",stdout); init(); doit(); return 0; } /* 2 1 7 3 5 2 7 1 8 2 10 2 7 3 2 8 2 5 */