「USACO12MAR」 Cows in a Skyscraper G

「USACO12MAR」 Cows in a Skyscraper G

题面

某谷P3052

基本思路

如果你贪心写的好,可以拿到差不多一半的分,然而正确性无法保证。

考虑状压

很明显可以将这 \(n\) 头奶牛是否被选的状态压起来。

所以,我们定义一个 \(f[s]\) 表示当前状态 \(s\) 下,所分的最少组数,

\(g[s]\) 表示当前状态 \(s\) 下,分成个若干个组中,剩余的最大的体积。

考虑转移

我们在放一头奶牛的时候,无非能放下 \((g[s] \geq w[i])\) 和不能放下 \((g[s] < w[i])\) 两种情况。

  • 若能放下,放后分的最少组数不变,剩余的最大体积要从若干个放前的状态 \(g[s] - w[i]\) 中取最大值。

  • 若放不下,放后分的最少组数加一,剩余的最大体积为 \(W - w[i]\) 中取最大值。

代码

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

#define DEBUG puts ("emmmm")

const int maxn = 3e5 + 50, INF = 0x3f3f3f3f;

using namespace std;

inline int read () {
	register int x = 0, w = 1;
	char ch = getchar ();
	for (; ch < '0' || ch > '9'; ch = getchar ()) if (ch == '-') w = -1;
	for (; ch >= '0' && ch <= '9'; ch = getchar ()) x = x * 10 + ch - '0';
	return x * w;
}

int n, W, maxs;
int w[maxn];
int f[maxn], g[maxn];

int main () {
	freopen ("fire.in", "r", stdin);
	n = read(), W = read(), maxs = (1 << n) - 1;
	for (register int i = 1; i <= n; i ++) w[i] = read();
	memset (f, 0x3f, sizeof f), f[0] = 1, g[0] = W;	
	for (register int s = 0; s <= maxs; s ++) {
		for (register int j = 1; j <= n; j ++) {
			register int x = 1 << j - 1;
			if (x & s) continue; // 若原来就有,直接跳过
			if (g[s] >= w[j] && f[s + x] >= f[s]) f[s + x] = f[s], g[s + x] = max (g[s + x], g[s] - w[j]); // 放得下
			else if (g[s] < w[j] && f[s + x] >= f[s] + 1) f[s + x] = f[s] + 1, g[s + x] = max (g[s + x], W - w[j]); // 放不下
		}		
	}
	printf ("%d\n", f[maxs]);
	return 0;
}
posted @ 2020-10-02 16:14  Rubyonlу  阅读(112)  评论(0编辑  收藏  举报