POJ 2923 Relocation ★(状态压缩+01背包)

题目大意:有n个物品,有两辆车载重分别是c1,c2.问需要多少趟能把物品运完。   好题~用到 状态压缩思想的01背包。   先枚举选若干个时的状态,总状态量为1<<n,判断集合里的物品能否用两辆车一次运走,如果能运走,那就把这个状态看成一个物品。预处理完找到tot个物品,再对这tot个物品进行01背包处理,每个物品的体积是state[i],价值是1,求必选n个物品的最少价值。   状态转移方程:dp[j|k] = min(dp[j|k],dp[k]+1) (k为state[i,1<=j<=(1<<n)-1])  
#include 
 
   
    
  
#include 
  
    
      #include 
     
       #include 
      
        #include 
       
         #include 
        
          #include 
         
           #include 
          
            #include 
            #include 
            
              #include 
             
               #include 
              
                #define MID(x,y) ((x+y)>>1) #define mem(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long LL; const int sup = 0x7fffffff; const int inf = -0x7fffffff; int n, c1, c2; int w[11]; vector 
               
                 state; int dp[1 << 11]; bool ifok(int state){ bool f[101]; int sum = 0; mem(f, 0); f[0] = 1; for (int i = 0; i < n; i ++) if ((1 << i) & state){ sum += w[i]; for (int j = c1; j >= w[i]; j --){ f[j] = f[j] || f[j-w[i]]; } } if (sum > c1 + c2) return 0; for (int i = 0; i <= c1; i ++) if (f[i] && (sum - i <= c2)) return 1; return 0; } int main(){ int t; scanf("%d", &t); for (int caseo = 1; caseo <= t; caseo ++){ scanf("%d %d %d", &n, &c1, &c2); for (int i = 1; i <= n; i ++) scanf("%d", &w[i]); for (int i = 0; i < (1 << n); i ++){ dp[i] = sup; if (ifok(i)){ state.push_back(i); } } dp[0] = 0; for (int i = 0; i < (int)state.size(); i ++){ for (int j = 0; j < (1 << n); j ++){ if (dp[j] != sup){ int p = state[i]; if (j & p == 0){ dp[j | p] == min(dp[j | p], dp[j] + 1); } } } } printf("Scenario #%d:\n", caseo); printf("%d\n", dp[(1< 
                
                    
                 
                
               
              
             
           
          
         
        
       
      
    
 
   

你可能感兴趣的:(location)