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

来源:互联网 发布:华中师范网络教育登陆 编辑:程序博客网 时间:2024/06/05 20:45

题目为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;}


原创粉丝点击