P3052 [USACO12MAR]摩天大楼里的奶牛Cows in a Skyscraper

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\n", dp[maxstate]);
	return 0;
	}
posted @ 2018-10-09 19:52  Tony_Double_Sky  阅读(156)  评论(0编辑  收藏  举报