[USACO12MAR]摩天大楼里的奶牛Cows in a Skyscraper——[状压DP]

【原题】
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头奶牛 ( 1 ≤ n ≤ 18 ) (1≤n≤18) (1n18),每一栋摩天大楼容量为W ( 1 ≤ W ≤ 1 0 8 ) , (1≤W≤10^8), (1W108),,每头奶牛有一个质量c[i] ( 1 ≤ c [ i ] ≤ W ) (1≤c[i]≤W) (1c[i]W),问将所有的奶牛安置需要几栋摩天大楼。

【输入格式】
第一行,两个数n,W
接下来n行,每行一个数c[i]

【输出格式】
一个数,安置所有的奶牛最少需要几栋摩天大楼。

S a m p l e    I n p u t Sample\;Input SampleInput

4 10
5
6
3
7

S a m p l e    O u t p u t Sample\;Output SampleOutput

3

【题意分析】
经典的状压DP题。 n ≤ 18 n≤18 n18可以卡掉大部分爆搜(超神搜索请无视)

d p [ i ] dp[i] dp[i]表示状态为 i i i时最少需要几栋摩天大楼。
r e s t [ i ] rest[i] rest[i]表示状态为 i i i时最后一栋摩天大楼还剩多少空间。

枚举所有状态 i i i,并且枚举奶牛 j j j,如果满足 r e s t [ i ] > = a [ j ] rest[i] >= a[j] rest[i]>=a[j],且 d p [ i ] < = d p [ i   ∣   ( 1 < < ( j − 1 ) ) ] dp[i] <= dp[i~|~(1 << (j-1))] dp[i]<=dp[i  (1<<(j1))](这里有=的原因是有可能 r e s t [ ] rest[] rest[]也要更新),那么
d p [ i   ∣   ( 1 < < ( j − 1 ) ) ] = d p [ i ] ; dp[i~|~(1 << (j-1))] = dp[i]; dp[i  (1<<(j1))]=dp[i]; r e s t [ i   ∣   ( 1 < < ( j − 1 ) ) ] = m a x ( r e s t [ i   ∣   ( 1 < < ( j − 1 ) ) ] , r e s t [ i ] − a [ j ] ) ; rest[i~|~(1 << (j-1))] = max (rest[i~|~(1 << (j-1))],rest[i] - a[j]); rest[i  (1<<(j1))]=max(rest[i  (1<<(j1))],rest[i]a[j]);
否则
d p [ i   ∣   ( 1 < < ( j − 1 ) ) ] = d p [ i ] + 1 ; dp[i~|~(1 << (j-1))] = dp[i] + 1; dp[i  (1<<(j1))]=dp[i]+1; r e s t [ i   ∣   ( 1 < < ( j − 1 ) ) ] = m a x ( r e s t [ i   ∣   ( 1 < < ( j − 1 ) ) ] , w − a [ j ] ) ; rest[i~|~(1 << (j-1))] = max (rest[i~|~(1 << (j-1))],w - a[j]); rest[i  (1<<(j1))]=max(rest[i  (1<<(j1))],wa[j]);

那么答案为 d p [ ( 1 < < n ) − 1 ] dp[(1<<n)-1] dp[(1<<n)1]

Code:

#include
#include
#include
#include
#include
#include
#define MAXN 20
using namespace std;

int a[MAXN],dp[1 << MAXN],rest[1 << MAXN];

template <typename T> inline T read (){
	register int s = 0,w = 1;
	register char ch = getchar ();
	while (!isdigit (ch)){if (ch == '-')w = -1;ch = getchar ();}
	while (isdigit (ch)){s = (s << 3) + (s << 1) + ch - '0';ch = getchar ();}
	return s*w;
}

int main (){
	int n = read <int> (),w = read <int> ();
	for (register int i = 1;i <= n;i++)
		a[i] = read <int> ();
	int SIT = (1 << n) - 1;//总状态值
	memset (dp,0x3f3f3f,sizeof (dp));//初始赋为最大
	dp[0] = 1,rest[0] = w;
	for (register int i = 0;i <= SIT;i++)//枚举状态
		for (register int j = 1;j <= n;j++){//枚举奶牛
			if ((i >> (j-1) & 1))continue;//在状态里了就不用了
			if (rest[i] >= a[j] && dp[i] <= dp[i|(1 << (j-1))]){//满足条件
				dp[i|(1 << (j-1))] = dp[i];
				rest[i|(1 << (j-1))] = max (rest[i|(1 << (j-1))],rest[i] - a[j]);
			}else {
				dp[i|(1 << (j-1))] = dp[i] + 1;
				rest[i|(1 << (j-1))] = max (rest[i|(1 << (j-1))],w - a[j]);
			}//更新
		}
	printf ("%d",dp[SIT]);
	return 0;
}

你可能感兴趣的:(状态压缩dp)