poj 1170 二解 之 六进制状态压缩DP

题目链接

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




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值