[Luogu3052] [USACO12MAR,Gold] Cows in a Skyscraper [状态压缩][dp]

[ L i n k \frak{Link} ]


一眼感觉是毒瘤背包
第二眼看到数据范围???

这么讲的话,weight的限制就得直接判断;又没有办法存
也就是说得记录每一组放了哪些?
这样的话压缩状态需要1818当然不行啦。
记录之前分了几组、选掉了哪些数、当前这组要选哪些?
三进制状压?选掉的是2,现在选掉的是1,没选的是0
318>3×108是没有前途的。

如果把21合并起来的话就可以变成:
枚举组数、每次更新状态之后、如果f(count,(1<<n)-1)≤w就跳。
有点像背包。

262144给开了个262000 不愧是我.jpg(


#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cstring>
#include<cctype>
using namespace std;
int n, w, c[20], F[2][262222], limit;
bool t;
int main() {
	scanf("%d%d", &n, &w);
	for (int i = 1; i <= n; ++i) {
		scanf("%d", &c[i]);
	}
	memset(F[0], 0x3f, sizeof(F));
	F[0][0] = 0;
	limit = (1<<n) - 1;
	for (int i = 1; i <= n; ++i) {
		t = i & 1;
		memset(F[t], 0x3f, sizeof(F[t]));
		for (int j = 0; j <= limit; ++j) {
			if (F[!t][j] > w) continue;
			F[t][j] = 0;
		}
		for (int v, j = 0; j < limit; ++j) {
			if (F[t][j] > w) continue;
			for (int k = 1; k <= n; ++k) {
				if (j&1<<k-1) continue;
				v = j|1<<k-1;
				F[t][v] = min(F[t][v], F[t][j] + c[k]);
			}
		}
		if(F[t][limit] <= w) {
			printf("%d", i);
			return 0;
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Estia_/article/details/83541267