题意“:有 b种商品 (0 <= b <= 5).,先依次给出 c(1 <= c <= 999,商品编码), k(1 <= k <= 5,需购买的数量), p (1 <= p <= 999,独立价格)。然后给出s(0 <= s <= 99)种优惠方案,给出的形式如下:每种方案包含n(1 <= n <= 5)种商品,每种商品包含c(编码),k(需购买数量)两个属性,最后是买这个方案中的所有商品给定的数量需要的总价格。问怎样选择优惠方案能最省钱?
用压缩状态表示商品的数量
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
/** 一共有五种商品 */
#define nMAX 6
/** 六进制基数数组,用六进制是因为每种商品的个数在0 ~ 5 */
const int base[5] = { 1, 6, 36, 216, 1296 };
/* 最大状态数是 六进制的 55555 = 7775 ,
* 其中55555 表示标号从0 到 4 的商品都各买了 5 个
*/
int dp[7776];
/* index[i] = j 表示编码为i 的商品的数组下标是j,
* 与上一种解中的code数组功能相同
*/
int index[1000];
/** 相应的商品数目 */
int num[nMAX];
/** 相应的商品价格 */
int price[nMAX];
/** 最大的表示状态的数 */
int count = 0;
/*
* 该方法计算从0 到 55555 的状态各需要花的钱数
*/
void init(){
for( int i = 1; i <= count; i ++ ){
int p = 0;
int ii = i;
for( int j = 0; j < 5; j ++ ){
int x = ii % 6;
p = p + price[j] * x;
ii /= 6;
}
dp[i] = p;
}
}
/* 该方法用于检查优惠方案是否能使用
* @name state1 需要购买的商品数
* @name state2 优惠方案规定的商品数
* return -1 不能使用
* return result 使用后剩下的商品数量
*/
int check( int state1, int state2 ){
int state = 0;
for( int i = 0; i < 5; i ++ ){
int x = state1 % 6;
int y = state2 % 6;
if( x < y )
return -1;
state1 /= 6;
state2 /= 6;
state += base[i] * ( x - y );
}
return state;
}
int main()
{
int i, j, b;
scanf("%d", &b);
int c;
for( i = 0; i < b; i ++ ){
scanf("%d%d%d", &c, &num[i], &price[i]);
/** 将商品编码转换为数组下标 */
index[c] = i;
/** 最大的表示状态的数 */
count += base[i] * num[i];
}
init();
/** 优惠方案总数 */
int s;
scanf("%d", &s);
for( i = 0; i < s; i ++ ){
/** 第i 种优惠方案所包含的商品种类数 ( < 5) */
int n;
scanf("%d", &n);
/** 该优惠方案所需商品数目的状态,即每一位上是该位表示的商品的数目 */
int state = 0;
for( j = 0; j < n; j ++ ){
int x, y;
scanf("%d%d", &x, &y );
state += y * base[index[x]];
}
/** 购买优惠方案所有包含的商品的总价格 */
int p;
scanf("%d", &p);
/** 动归方程,比较使用该优惠条件前后的价格情况,取较小值 */
for( j = 0; j <= count; j ++ ){
int tmp_state = check( j, state );
if( tmp_state != -1 ){
if( dp[j] > dp[tmp_state] + p )
dp[j] = dp[tmp_state] + p;
}
}
}
printf("%d\n", dp[count]);
return 0;
}