POJ 1170 shopping offers 状态压缩 记忆化搜索

题意:

给你n件物品,三个参数描述该物品,编号,数量(<=5),每件价格。 n <= 5

然后给你s种方案,第一个数位商品种类对数,然后是该商品型号,数量,最后一个数是该方案价格。

求把所有物品买完最低的价格。

算法1:

商品种类很少,<= 5

开个五维数组

int dp[5][5][5][5][5],dp[a][b][c][d][e][f],表示第1中物品买a件,第2种物品买b件,。。,第5种物品买f件所需要价格

然后DFS枚举每一种方案,记忆化搜索,即可以算出最优解。

View Code
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

struct node
{
  int n[6]; //保存每种商品数量
  int price; //保存该种方案的价格
}plan[120];

const int inf = 0x3f3f3f3f;
int num[10]; //保存要购买的数量
int M; //保存所有方案
int code[1100]; //映射下标
int F[6][6][6][6][6]; //表示1号商品购买六,2号商品购买六,。。。5号商品购买六种,所花的钱

int DFS( int n1, int n2, int n3, int n4, int n5)
{  
   if( F[n1][n2][n3][n4][n5] != -1)  
       return  F[n1][n2][n3][n4][n5]; //记忆化搜索 
   int Minx = inf;
   for( int i = 1; i <= M; i++)
   {
      if( n1 >= plan[i].n[1] &&  n2 >= plan[i].n[2] && n3 >= plan[i].n[3] && n4 >= plan[i].n[4] && n5 >= plan[i].n[5])
      {
       int temp = DFS(n1 - plan[i].n[1], n2 - plan[i].n[2], n3 - plan[i].n[3], n4 - plan[i].n[4], n5 - plan[i].n[5]) + plan[i].price;
       if( temp < Minx )
          Minx = temp;
      }       
        
   }     
   F[n1][n2][n3][n4][n5] = Minx;
   return F[n1][n2][n3][n4][n5];
}
 
int main( )
{
   int N, c, k, p, i, t;
   while( scanf("%d",&N) != EOF )
   {
     memset(plan, 0, sizeof(plan));
     memset(F, -1, sizeof(F));
     F[0][0][0][0][0] = 0;
     for(i = 1; i <= N; i++)
     {
       scanf("%d%d%d",&c, &k, &p);//读入标号,数量,价格 
       code[c] = i; //映射下标 
       num[i] = k;  //保存要购买的数量
       //第i种方案
       plan[i].price = p;
       plan[i].n[code[c]] = 1; 
     }          
     scanf("%d",&M);
     M += N;
     for(  ; i <= M; i++)
     {
        scanf("%d",&t);
        for( int j = 1; j <= t; j++)
        {
           scanf("%d%d",&c, &k); //读入商品标号与数量
           plan[i].n[code[c]] = k;     
        }         
        scanf("%d",&p); //读入组合后的价格
        plan[i].price = p;   
     }
     printf("%d\n",DFS(num[1], num[2], num[3], num[4], num[5]));
     
   }    
   return 0; 
}

算法2:

状态压缩:

最大为5,我们可以用6进制12345来表示第1中方案选择了5件,第2种方案选择了2件。。。

把十进制转为六进制。。

dp[state]表示该状态最优解。。

最后枚举state既可。。

奇葩。。神奇的状态压缩,就怕你想不到

View Code
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

//li
int dp[11000];
int num[20]; //保存数量 
int price[20]; //保存价格 
int code[1100];
int st[10] = {1, 6, 36, 216, 1296,  7776, 46656 };
int state;//总的状态i
struct node
{
  int s; //该方案的状态值
  int p; //该方案话费
}plan[110]; 
int N, M;
const int inf = 0x3f3f3f3f;
//十进制转为六进制 
bool jugde( int a, int b)
{
  for( int i = 0; i < N; i++)
  {
     if( (a % 6 + b % 6) > num[i] )
         return false;
      a = a / 6;
      b = b / 6;
  }     
  return true;   
}

int sum( int x)
{
  int sumx = 0;
  for( int i = 0; i < N; i++)
  {
      sumx += (x % 6) * price[i];
      x = x / 6;     
  }    
  return sumx;  
}

int main( )
{
  int p, k, c, t;
  while( scanf("%d",&N) != EOF)
  {
     state = 0;
     memset(plan, 0, sizeof(plan));
     for( int i = 0; i < N; i++)
     {
         scanf("%d%d%d",&c, &k, &p);
         code[c] = i;        
         num[i] = k;
         price[i] = p;
         state += st[i] * k;                
     }
     scanf("%d",&M);
     for( int i = 1; i <= M; i++)
     {
         scanf("%d",&t);
         for( int j = 1; j <= t; j++)
         {
           scanf("%d%d",&c,&k);
           plan[i].s += st[code[c]] * k;      
         }
         scanf("%d",&p);
         plan[i].p = p;      
     }
     for( int i = 1; i <= state; i++)
          dp[i] = inf;
     dp[0] = 0;
     for( int j = 1; j <= M; j++)
     {
         for( int i = 0; i <= state; i++)
         {
           if( i + plan[j].s <= state && jugde(i, plan[j].s))
           {
             if( dp[i + plan[j].s] > dp[i] + plan[j].p && dp[i] != inf)
                 dp[i + plan[j].s] = dp[i] + plan[j].p;    
             
           }
         }
     }
     int ans = inf;
     for( int x = 0; x <= state; x++)
     {
        int t = sum(state - x );
        if( ans > t + dp[x] )
            ans = t + dp[x];          
          
     }
     printf("%d\n", ans);  
  }
  return 0;    
}

posted on 2012-08-06 15:48  more think, more gains  阅读(295)  评论(0编辑  收藏  举报

导航