pku 1170 Shopping Offers 状态DP或者说最短路都可以


看图说话,描述题目- -
有若干类商品,然后每个商品有一定的价格,商店推出捆绑销售优惠,购买指定组合的物品可以有一定的优惠。
给出目标状态,要求花最少的钱买到指定数量的物品。
由于数据量很小,很快想到压缩状态,然后DP求从初始状态到末状态的最小花费。
这种题目我喜欢转化为图,把每个状态看作一个节点,然后求这个图上从起点到终点的最长链。对于某些看似存在后效性的状态DP中,可以采用SPFA算法,消除后效性。
贴代码
  1 # include <cstdio>
  2 # include <cstring>
  3 using namespace std;
  4 int dp[100000];
  5 # define encode(n1,n2,n3,n4,n5) (((((((((n1)<<3)|(n2))<<3)|(n3))<<3)|(n4))<<3)|(n5))
  6 # define getn1(sta) ((sta)>>12)
  7 # define getn2(sta) (((sta)>>9)&7)
  8 # define getn3(sta) (((sta)>>6)&7)
  9 # define getn4(sta) (((sta)>>3)&7)
 10 # define getn5(sta) ((sta)&7)
 11 # define min(a,b) ((a)<(b)?(a):(b))
 12 int pri[200][2],count=0;
 13 int solve(int pos)
 14 {
 15    if(dp[pos]!=-1return dp[pos];
 16    else if(pos==0return 0;
 17    else
 18    {
 19      //  int show1=getn1(pos),show2=getn2(pos),show3=getn3(pos),show4=getn4(pos),show5=getn5(pos);
 20        int minnum=0xfffffff;
 21        for(int i=count-1;i>=0;i--)
 22           if(getn1(pos)-getn1(pri[i][0])>=0&&
 23              getn2(pos)-getn2(pri[i][0])>=0&&
 24              getn3(pos)-getn3(pri[i][0])>=0&&
 25              getn4(pos)-getn4(pri[i][0])>=0&&
 26              getn5(pos)-getn5(pri[i][0])>=0&&
 27              solve(encode(getn1(pos)-getn1(pri[i][0]),getn2(pos)-getn2(pri[i][0]),getn3(pos)-getn3(pri[i][0]),getn4(pos)-getn4(pri[i][0]),getn5(pos)-getn5(pri[i][0])))+pri[i][1]<minnum)
 28                 minnum=solve(encode(getn1(pos)-getn1(pri[i][0]),getn2(pos)-getn2(pri[i][0]),getn3(pos)-getn3(pri[i][0]),getn4(pos)-getn4(pri[i][0]),getn5(pos)-getn5(pri[i][0])))+pri[i][1];
 29        dp[pos]=minnum;
 30        return minnum;
 31    }
 32 }
 33 int main()
 34 {
 35   //  FILE *in1=fopen("input.txt","r"),*in2=fopen("offer.txt","r");
 36   //  FILE *out=fopen("output.txt","w");
 37     int num,co=1;
 38     int map[1000];
 39     memset(map,-1,sizeof(map));
 40     memset(dp,-1,sizeof(dp));
 41     scanf("%d",&num);
 42     int ori=0;
 43     while(num--)
 44     {
 45        int c,k,p;
 46        scanf("%d%d%d",&c,&k,&p);
 47        if(map[c]==-1) map[c]=co++;
 48        c=map[c];
 49        switch(c)
 50        {
 51          case 1:       
 52             pri[count][0]=encode(1,0,0,0,0);
 53             ori|=encode(k,0,0,0,0);
 54             break;
 55          case 2:
 56             pri[count][0]=encode(0,1,0,0,0);
 57             ori|=encode(0,k,0,0,0);
 58             break;
 59          case 3:
 60             pri[count][0]=encode(0,0,1,0,0);
 61             ori|=encode(0,0,k,0,0);
 62             break;
 63          case 4:
 64             pri[count][0]=encode(0,0,0,1,0);
 65             ori|=encode(0,0,0,k,0);
 66             break;
 67          case 5:
 68             pri[count][0]=encode(0,0,0,0,1);
 69             ori|=encode(0,0,0,0,k);
 70             break;
 71        };
 72        pri[count++][1]=p;   
 73     }
 74     scanf("%d",&num);
 75     while(num--)
 76     {
 77        int n;
 78        pri[count][0]=0;
 79        bool flag=true;
 80        scanf("%d",&n);
 81        while(n--)
 82        {
 83           int c,k;
 84           scanf("%d%d",&c,&k);
 85           if(map[c]==-1)
 86              flag=false;
 87           if(flag)
 88           {
 89                switch(map[c])
 90                {
 91                  case 1:       
 92                     pri[count][0]|=encode(k,0,0,0,0);
 93                     break;
 94                  case 2:
 95                     pri[count][0]|=encode(0,k,0,0,0);
 96                     break;
 97                  case 3:
 98                     pri[count][0]|=encode(0,0,k,0,0);
 99                     break;
100                  case 4:
101                     pri[count][0]|=encode(0,0,0,k,0);
102                     break;
103                  case 5:
104                     pri[count][0]|=encode(0,0,0,0,k);
105                     break;
106                };
107           }
108        }
109        scanf("%d",&n);
110        if(flag)
111            pri[count++][1]=n;
112     }
113    // for(int i=0;i<count;i++)
114      // printf("%d %d %d %d %d\n",getn1(pri[i][0]),getn2(pri[i][0]),getn3(pri[i][0]),getn4(pri[i][0]),getn5(pri[i][0]));
115     //printf("%d %d %d %d %d\n",getn1(ori),getn2(ori),getn3(ori),getn4(ori),getn5(ori));
116     printf("%d\n",solve(ori));
117    // fclose(in1);
118     //fclose(in2);
119    // fclose(out);
120     return 0;
121     
122 }
123 


posted on 2010-10-22 01:59 yzhw 阅读(139) 评论(0)  编辑 收藏 引用 所属分类: DP


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


<2010年10月>
262728293012
3456789
10111213141516
17181920212223
24252627282930
31123456

导航

统计

公告

统计系统

留言簿(1)

随笔分类(227)

文章分类(2)

OJ

最新随笔

搜索

积分与排名

最新评论

阅读排行榜