牛客-装货物
题目传送门
sol:题目的数据范围就是对解决方案的一种提示,原先以为当数据范围只有$20$的时候都是dfs或者二进制枚举这种,从这题了解到还有状压dp。不解释了,反正就是状压dp,做的不多,记录一下。
- 状压dp
#include <bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<int, int> PII; const int INF = 0x3f3f3f3f; const int MAXN = 22; int a[MAXN]; // dp1最小箱子消耗,dp2在最小箱子消耗的前提下最后一个箱子的最大剩余 int dp1[1 << MAXN | 10], dp2[1 << MAXN | 10]; int main() { int t; scanf("%d", &t); while (t--) { int n, m, w, _max = 0; scanf("%d%d%d", &n, &m, &w); for (int i = 0; i < n; i++) { //状压dp下标还是从0开始好了,从1开始写了几次都wa scanf("%d", &a[i]); _max = max(_max, a[i]); } if (_max > w) { puts("No"); continue; } memset(dp1, INF, sizeof(int) * (1 << n)); memset(dp2, 0, sizeof(int) * (1 << n)); dp1[0] = 0; for (int i = 0; i < (1 << n); i++) { for (int j = 0; j < n; j++) { int k = 1 << j; if (i & k) continue; if (dp2[i] >= a[j] && (dp1[i] < dp1[i | k] || dp1[i] == dp1[i | k] && dp2[i | k] < dp2[i] - a[j])) { dp1[i | k] = dp1[i]; dp2[i | k] = dp2[i] - a[j]; } else if (dp1[i] + 1 <= dp1[i | k]) { dp1[i | k] = dp1[i] + 1; dp2[i | k] = w - a[j]; } } } // printf("%d\n", dp1[(1 << n) - 1]); puts(dp1[(1 << n) - 1] <= m ? "Yes" : "No"); } return 0; }
- 爆搜
#include <bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<int, int> PII; int a[30], c[30]; int n, m, w; bool dfs(int i) { if (i > n) return true; int k = min(i + 1, m); // 这个优化很关键 for (int j = 1; j <= k; j++) { if (c[j] + a[i] <= w) { c[j] += a[i]; if (dfs(i + 1)) return true; c[j] -= a[i]; } } return false; } int main() { int t; scanf("%d", &t); while (t--) { scanf("%d%d%d", &n, &m, &w); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); sort(a + 1, a + 1 + n, greater<int>()); if (a[1] > w) { puts("No"); continue; } if (m >= n) { puts("Yes"); continue; } memset(c, 0, sizeof(c)); puts(dfs(1) ? "Yes" : "No"); } return 0; }
数据比较水,在爆搜优化到极致的情况下能AC,自己写的时候没有那个关键的优化总是超时,还是挺妙的。