USACO Training Section 3.3 Shopping Offers

英文原题 
中文题译

这是个与日常生活相关的题。商场促销,把许多商品捆绑销售并优惠价格,一个精明的先生拿着老婆给的购物清单来买东西,他准备给自己存点私房钱,所以,他不打算为省钱买不需要的东西(如果是女士来,就会这样),为此他扫描了一遍所有的优惠活动,决定按最优方式来购买以节省最多的钱。

数据限制条件:商品种类最多999项,优惠活动最多999项,每项最多捆绑5件商品,优惠价总是比原价总和便宜。先生要买的物品最多5种,每种最多5件。

分析:虽然商品种类最多999项,但既然先生不准备买多余的东西,可认为只有最多5项,凡是优惠条目中包含不需要的商品的一律忽略。这是预处理过程,不妨设要买的商品就是1-5编号。每样最多5件,状态为6^5=7776,每个状态<a_i>(0<=i<5,0<=a_i<=5)有:
best<a_i>=min{best<a_i-b_j_i>+price_j|j为优惠方案,b_j_i为其中物品i的数量,price_j为其价格},
在优惠方案中加入原始报价(即只有一件物品数量为1)也作为一种方案,即不需特殊处理了。我倾向于用一维数组表示状态而不是5维,更具有一般性吧。

实现:
1. 在字符串缓冲区中读取内容时用sscanf不方便,改用isstream ;
2. DP过程中可以加点优化,对每个数,只要某个数值大于需要的相应位,就可跳过,不需完全搜索。
一次通过,很顺利。

/*
ID: blackco3
TASK: shopping
LANG: C++
*/
#include <iostream>
#include <sstream>
#include <string>
#include <memory.h>
using namespace std;
const int _max_special_(1000), _max_type_(1000), _max_line_len_(256);
const int _max_type_need_(5),  _max_num_need_(5),  _max_comb_(7776)/*as (5+1)^5 */;

int n_type(0), n_tot_special(0), need[_max_type_], max_need(0);
int nums[_max_type_], best[_max_comb_] ;
struct t_special {
	int n_type,	types[_max_type_need_], nums[_max_num_need_], price ;
} specials[_max_special_+_max_type_need_], *ps_end=specials ;

int main() {
	freopen("shopping.in", "r", stdin);
	freopen("shopping.out", "w", stdout);

	char lines[_max_special_][_max_line_len_+1] ;
	fgets( lines[0], _max_line_len_, stdin) ;
	sscanf( lines[0], "%d", &n_tot_special ) ;
	for( int i=0; i<n_tot_special; i++ )
		fgets( lines[i], _max_line_len_, stdin );
	memset( need, 0xff, sizeof(need) );

	cin >> n_type ;
	for( int i=0; i<n_type; i++ ){
		int type ;
		cin >> type >> nums[i] >> ps_end->price ;
		need[type] = i , ps_end->n_type=1, ps_end->nums[0] =1 , ps_end->types[0] = i, ps_end++ ;  
		max_need = nums[i]>max_need ? nums[i] : max_need ;
	}

	istringstream iss ;
	for( int i=0; i<n_tot_special; i++ ){
		iss.str(lines[i]), iss >> ps_end->n_type ;
		if( ps_end->n_type > n_type )
			continue ;
		int ignore=false ;
		for( int j=0; j<ps_end->n_type; j++ ){
			iss >> ps_end->types[j] >> ps_end->nums[j] ;
			if( need[ ps_end->types[j] ]==-1 ){
				ignore=true ;
				break ;
			}
			ps_end->types[j] = need[ ps_end->types[j] ] ;
		}
		if( ignore )
			continue ;
		iss >> ps_end->price ;
		ps_end++ ;
	}

	int n_comb=0, pow[_max_num_need_], cur_num[_max_type_need_] ;
	max_need++ ; /* to get 0..max_need*/
	for( int i=0 ; i<n_type; i++ ){
		n_comb = max_need*n_comb + nums[n_type-1-i];
		cur_num[i] = 0 , pow[i] = i ? pow[i-1]*max_need : 1 ;
	}

	for( int i_comb=1; i_comb<=n_comb; i_comb++ ){
		for( int pos=0; (++cur_num[pos])==max_need; pos++)
			cur_num[pos] = 0 ;
		int min_val=0x7fffffff ;
		for( t_special *pc=specials; pc!=ps_end; pc++ ){
			int ignore=false, pre_comb=i_comb ;
			for( int it=0; it<pc->n_type; it++ ){
				if( pc->nums[it] > cur_num[pc->types[it]] ){
					ignore=true ;
					break ;
				}
				pre_comb -= pc->nums[it]*pow[pc->types[it]] ;
			}
			if( ignore )
				continue ;
			min_val = min_val <= best[pre_comb] + pc->price ? min_val : best[pre_comb] + pc->price ;
		}
		best[i_comb] = min_val ;
	}

	cout << best[n_comb] << endl ;
	return 0;
}

你可能感兴趣的:(c,生活,活动,J#,asp)