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

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

pku 1170 Shopping Offers 状态DP或者说最短路都可以_第1张图片
看图说话,描述题目- -
有若干类商品,然后每个商品有一定的价格,商店推出捆绑销售优惠,购买指定组合的物品可以有一定的优惠。
给出目标状态,要求花最少的钱买到指定数量的物品。
由于数据量很小,很快想到压缩状态,然后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] !=- 1 return  dp[pos];
 16      else   if (pos == 0 return   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 


你可能感兴趣的:(pku 1170 Shopping Offers 状态DP或者说最短路都可以)