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