P3052 [USACO12MAR]摩天大楼里的奶牛Cows in a Skyscraper
给出n个物品,体积为w[i],现把其分成若干组,要求每组总体积<=W,问最小分组。(n<=18)
Solution
数据范围识状压(其实迭代加深也可以, 答案不会超过18)
每个状压状态有两个参数:
(dp[i]) : (i) 状态的最少需要分几组
(w[i]) : (i) 状态装的最少的最少承载多重
根据贪心, 我们必然优先满足 (dp[i]) 较小, 在这个基础上再满足 (w[i]) 尽可能小
那么大体框架就差不多定型了
具体看注释
Code
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#include<climits>
#define LL long long
#define REP(i, x, y) for(int i = (x);i <= (y);i++)
using namespace std;
int RD(){
int out = 0,flag = 1;char c = getchar();
while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
return flag * out;
}
const int maxn = (1 << 19);
int num, W;
int a[25], one[25];
int dp[maxn], w[maxn];
int main(){
num = RD(), W = RD();
REP(i, 1, num)a[i] = RD(), one[i] = (1 << (i - 1));
int maxstate = (1 << num) - 1;
REP(i, 0, maxstate)dp[i] = w[i] = 1e9;
dp[0] = 0;
REP(i, 0, maxstate){
REP(j, 1, num){
if(i & one[j])continue;
if(dp[i] <= dp[i | one[j]] && w[i] + a[j] <= W){//若是现在的状态还能放下j
dp[i | one[j]] = dp[i];//更新
w[i | one[j]] = min(w[i | one[j]], w[i] + a[j]);
}
else if(w[i] + a[j] > W && dp[i] + 1 <= dp[i | one[j]]){//放不下,但又能更新
dp[i | one[j]] = dp[i] + 1;
w[i | one[j]] = min(w[i | one[j]], a[j]);
}
}
}
printf("%d
", dp[maxstate]);
return 0;
}