poj 1170 Shopping Offers 动态规划绝对经典题目

本文详细介绍了如何通过动态规划和巧妙运用六进制数来解决POJ平台上的1170号问题,即在商品数量不超过5的情况下,如何通过套餐优惠策略最小化总花费。文章深入解析了问题的解决方案,包括状态转移方程的建立、六进制数的应用以及最终的最优解求取过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目为POJ 1170题目链接:http://poj.org/problem?id=1170

#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int M=6; const int inf=20000; /* 这个题太妙了,因为每种商品的数量不超过5 这就可以很妙的利用一个六进制的数来记录相应的每种物品的数量,余数为1-5正好合适 动太规划每次都能给人带来太多的惊喜! 题目链接:http://poj.org/problem?id=1170 */ const int base[6]={1,6,36,216,1296,7776}; struct Offer{ int st; int price; Offer(){ st=0; price=0; } }; struct Item{ int cnt; int p; }; int n,m,id,state; Offer offer[101]; Item item[5]; int hash[1000]; int dp[10000]; bool check(int x,int y){//检查一下五种物品的x状态和y状态是否满足各种物品的数量都符合给定物品的数量 即小于等于 如果超出了显然不是有效状态 for(int i=0;i<n;i++){ if((x%6+y%6)>item[i].cnt){ return false; } x/=6; y/=6; } return true; } int calculate(int state){//求不用套餐时状态为state时的花费 int cost=0; for(int i=0;state;i++){ cost+=(state%6)*item[i].p;//一看就能明白,这就是取出各种物品的数量然后乘上单价 state/=6; } return cost; } int min(int a,int b){ return a<b?a:b; } int main(){ int i,j,k,code,cnt,cost,p; state=0; scanf("%d",&n); for(i=0;i<n;i++){ scanf("%d%d%d",&code,&item[i].cnt,&item[i].p); hash[code]=i; state+=base[i]*item[i].cnt; } scanf("%d",&m); for(i=0;i<m;i++){ scanf("%d",&p); for(j=0;j<p;j++){ scanf("%d%d",&code,&cnt); offer[i].st+=base[hash[code]]*cnt; } scanf("%d",&offer[i].price); } for(i=0;i<=state;i++)dp[i]=inf; dp[0]=0;//这个地方当state为0时即各种东西数量都为0 一定要注意初始化 因为这个地方调了很长时间都没发现 for(i=0;i<m;i++){//遍历各种套餐,看看加套餐和不加套餐的情况下相同数量相同产品那个花费更低 for(j=0;j<=state;j++){ if(dp[j]==inf)continue; if(j+offer[i].st<=state && check(j,offer[i].st)){ if(dp[j+offer[i].st]>dp[j]+offer[i].price){ dp[j+offer[i].st]=dp[j]+offer[i].price; } } } } int ans=inf,temp; for(i=0;i<=state;i++){//遍历各种东状态一部分用套餐一部分不用套餐时的花费,找最小的 temp=calculate(state-i); ans=min(temp+dp[i],ans); } printf("%d\n",ans); return 0; }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值