poj1170 状态压缩

因为每种物品最多五个,总共五种物品,所以可以将状态存为6进制的整数。

先对每一种special offer进行dp, 转移方程为  dp[ i + offfer[k].stt ] = MIN( dp[ i + offer[k].stt , dp[ i ] + offer[k].prc ), 当然状态转移前,要进行判断是否可转移,

若当前状态下 的某种物品数量加上当前的special offer中的这种物品数量后,超过总共拥有这种物品的数量,此时是不可转移的。

#include <iostream>
#include <cmath>
using namespace std;

#define M 6

struct Item
{
	int num, prc; //num为每种物品的数量,prc为单价
} items[5];

struct Offer
{
	int stt, prc; //stt是将每一种special offer中各种物品压缩成的状态,prc为对应的优惠价
} offer[100];

int hash[1000]; //hash[k]的值为product code为k的物品的下标
int dp[8000];

inline int MIN(int a, int b)
{
	return a > b ? b : a;
}

 //判断当前状态为state时,加上stt(stt为special offer)后,每一种物品是否超过
 //这种物品的总数,若超过,则当前状态不能靠这个stt进行转移
bool check(int state, int stt) 
{
    int id = 0;

	while(state > 0 && stt > 0){
	     if(state % M + stt % M > items[id].num)
			 return false;
		 state /= M;
		 stt /= M;
		 id++;
	}
	return true;
}

int cal_left(int state)
{
	int left = 0, id = 0;
    
    while(state > 0)
	{
	   left += (state % M) * items[id].prc;
	   state /= M;
	   id++;
	}
	return left;
}

int main()
{
	int state;
    int b, s, n;
    int i, j;
    int code, num;

	state = 0;
	memset(hash, -1, sizeof(hash));
	scanf("%d", &b);
	for(i = 0; i < b; i++){  
		scanf("%d%d%d", &code, &items[i].num, &items[i].prc);
		hash[code] = i; 
		state += items[i].num * (int)pow(6.0, i*1.0); //篮子里的所有物品压缩为状态state
	}
    
    scanf("%d", &s);
	for(i = 0; i < s; i++){
		offer[i].stt = 0;
		scanf("%d", &n);
		for(j = 0; j < n; j++){
			scanf("%d%d", &code, &num);
			offer[i].stt += (int)pow(6.0, hash[code]*1.0) * num; //压缩special offer
		}
		scanf("%d", &offer[i].prc);
	}

    for(i = 1; i <= state; i++) 
		dp[i] = INT_MAX;
	dp[0] = 0; //注意初始化
    for(i = 0; i <= state; i++){
		if(dp[i] == INT_MAX) continue;
		for(j = 0; j < s; j++){
			if(i+offer[j].stt <= state && check(i, offer[j].stt)){  //状态之间可以直接相加(以前我不知道这点),判断是否可转移
			    dp[i+offer[j].stt] = MIN(dp[i+offer[j].stt], dp[i]+offer[j].prc);
			}
		}
	}
	//计算剩余的按原价购买的物品与通过special offer购买的物品的总价格
	//最小值即为答案
	int ans = INT_MAX;
	for(i = 0; i <= state; i++){ 
        if(dp[i] == INT_MAX) continue;
		ans = MIN(ans, dp[i] + cal_left(state-i)); 
	}
	printf("%d\n", ans);
	return 0;
}


 

你可能感兴趣的:(poj1170 状态压缩)