题目描述
A little known fact about Bessie and friends is that they love stair climbing races. A better known fact is that cows really don't like going down stairs. So after the cows finish racing to the top of their favorite skyscraper, they had a problem. Refusing to climb back down using the stairs, the cows are forced to use the elevator in order to get back to the ground floor.
The elevator has a maximum weight capacity of W (1 <= W <= 100,000,000) pounds and cow i weighs C_i (1 <= C_i <= W) pounds. Please help Bessie figure out how to get all the N (1 <= N <= 18) of the cows to the ground floor using the least number of elevator rides. The sum of the weights of the cows on each elevator ride must be no larger than W.
给出n个物品,体积为w[i],现把其分成若干组,要求每组总体积<=W,问最小分组。(n<=18)
输入输出格式
输入格式
Line 1: N and W separated by a space.
Lines 2..1+N: Line i+1 contains the integer C_i, giving the weight of one of the cows.
输出格式
Line 1: A single integer, R, indicating the minimum number of elevator rides needed.
输入输出样例
输入样例#1
4 10
5
6
3
7
输出样例#1
3
解题思路
看到 n 的数据范围这么小,立刻想到这题一定是一道状态压缩,但是如果我们按照常规思路把奶牛选不选的状态和总重量都记进状态中的话很显然时间复杂度和空间复杂度都是无法承受的,所以我们考虑将答案记入状态数组的维度中
因此我们定义数组 f [ i ] [ j ] 表示现在用了 i 个电梯,每个奶牛选不选的状态为 j 时最后用的电梯的最小载重量,所以我们枚举可能的每种状态 j ,当 f [ i ] [ j ] 是可选用的状态时,我们开始枚举每一个奶牛 k ,如果奶牛 k 不在此时的 j 状态中,则可以进行状态转移,然后我们可以贪心的考虑一下,如果 k 可以放在当前最后一个电梯中,即f [ i ] [ j ] + w [ k ] <=W时,把 k 放在 i 这个电梯中显然是最优解,那么我们的状态转移方程就是
f [ i ] [ j | ( 1 << ( k - 1) ) ] = min ( f [ i ] [ j | ( 1 << ( k - 1 ) ) ] , f [ i ] [ j ] + w [ k ] ;
相反,如果 k 这个奶牛无法放在最后这个电梯 i 中时,我们就只能把他放在下一个电梯 i + 1 中,状态转移方程为:
f [ i + 1 ] [ j | ( 1 << ( k - 1 ) ) ] = min( f [ i ] [ j | ( 1 << ( k - 1 ) ) ] , w [ k ] ;
下面是C++代码
C++代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define rr register
using namespace std;
const int maxn=20;
const int inf=0x3f3f3f3f;
int n,W,tot,ans;
int f[20][1<<19],w[maxn];
inline int read(){
int chtholly=0,willem=1;char c=getchar();
while(c<'0' || c>'9'){if(c=='-')willem=-1;c=getchar();}
while(c<='9' && c>='0'){chtholly=chtholly*10+(int)(c-'0');c=getchar();}
return chtholly*willem;
}
int main(){
memset(f,inf,sizeof(f));
n=read(),W=read();
for(rr int i=1;i<=n;i++)w[i]=read();
tot=(1<<n)-1;
for(rr int i=0;i<n;i++)f[1][1<<i]=w[i+1];
for(rr int i=0;i<=n;i++)for(rr int j=0;j<=tot;j++)if(f[i][j]!=inf){
for(rr int k=1;k<=n;k++)if(!(j&(1<<(k-1)))){
if(f[i][j]+w[k]<=W)
f[i][j|(1<<(k-1))]=min(f[i][j|(1<<(k-1))],f[i][j]+w[k]);
else
f[i+1][j|(1<<(k-1))]=min(f[i][j|(1<<(k-1))],w[k]);
}
}
for(rr int i=0;i<=n;i++)if(f[i][tot]!=inf){
ans=i;break;
}
printf("%d\n",ans);
return 0;
}