for (int i = 1; i <= n; i++) for (int j = 0; j <= W; j++) for (int k = 0; k * w[i] <= j; k++) //选取几个物品 dp[i][j] = max(dp[i][j], dp[i - 1][j - k * w[i]] + k * v[i]);
实际上,我们可以发现,取 件物品可以从取 件转移过来,那么我们就可以将 的循环优化掉
1 2 3 4 5 6
for (int i = 1; i <= n; i++) for (int j = 0; j <= W; j++){ dp[i][j] = dp[i - 1][j]; if (j >= w[i]) dp[i][j] = max(dp[i][j], dp[i][j - w[i]] + v[i]); }
和 01 背包 类似地压缩成一维
1 2 3
for (int i = 1; i <= n; i++) for (int j = w[i]; j <= W; j++) dp[j] = max(dp[j], dp[j - w[i]] + v[i]);
for (int i = 1; i <= n; i++){ for (int j = W; j >= 0; j--) for (int k = 0; k <= s[i]; k++){ if (j - k * w[i] < 0) break; dp[j] = max(dp[j], dp[j - k * w[i]] + k * v[i]); }
上述方法的时间复杂度为 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
for (int i = 1; i <= n; i++){ scanf("%lld%lld%lld", &x, &y, &s); //x 为体积, y 为价值, s 为数量 t = 1; while (s >= t){ w[++num] = x * t; v[num] = y * t; s -= t; t *= 2; } w[++num] = x * s; v[num] = y * s; } for (int i = 1; i <= num; i++) for (int j = W; j >= w[i]; j--) dp[j] = max(dp[j], dp[j - w[i]] + v[i]);
#include<bits/stdc++.h> usingnamespace std; constint N = 2e5 + 10; int n, W, w, v, s, f[N], g[N], q[N]; intmain(){ ios::sync_with_stdio(false);cin.tie(0); cin >> n >> W; for (int i = 0; i < n; i ++ ){ memcpy ( g, f, sizeof f); cin >> w >> v >> s; for (int j = 0; j < w; j ++ ){ int head = 0, tail = -1; for (int k = j; k <= W; k += w){ if ( head <= tail && k - s * w > q[head] ) head ++ ;//保证队列长度 <= s while ( head <= tail && g[q[tail]] - (q[tail] - j) / w * v <= g[k] - (k - j) / w * v ) tail -- ;//保证队列单调递减 q[ ++ tail] = k; f[k] = g[q[head]] + (k - q[head]) / w * v; } } } cout << f[W] << "\n"; return0; }
/* pos 表示当前枚举到第几位 sum 表示 d 出现的次数 limit 为 1 表示枚举的数字有限制 zero 为 1 表示有前导 0 d 表示要计算出现次数的数 */ constint N = 15; LL dp[N][N]; int num[N]; LL dfs(int pos, LL sum, int limit, int zero, int d){ if (pos == 0) return sum; if (!limit && !zero && dp[pos][sum] != -1) return dp[pos][sum]; LL ans = 0; int up = (limit ? num[pos] : 9); for (int i = 0; i <= up; i++) { ans += dfs(pos - 1, sum + ((!zero || i) && (i == d)), limit && (i == num[pos]), zero && (i == 0), d); } if (!limit && !zero) dp[pos][sum] = ans; return ans; } LL solve(LL x, int d){ memset(dp, -1, sizeof dp); int len = 0; while (x) { num[++len] = x % 10; x /= 10; } returndfs(len, 0, 1, 1, d); }
#include<bits/stdc++.h> #define int long long usingnamespace std; constexprint MAXN = 24 + 10; int a[MAXN], mod, f[MAXN][MAXN * 10][MAXN * 10];
intdfs(int pos, int sum, int cur, bool lead0, bool lim){ if (!pos)return !lead0 && sum == mod && cur == 0; int& now = f[pos][cur][sum]; if (!lead0 && !lim && ~now)return now; int up = lim ? a[pos] : 9, res = 0; for (int i = 0;i <= up;++i) res += dfs(pos - 1, sum + i, (cur * 10 + i) % mod, lead0 && !i, lim && i == up); if (!lead0 && !lim)now = res; return res; }
signedmain(){ ios::sync_with_stdio(false); cin.tie(0), cout.tie(0); int n;cin >> n; int len = 0; while (n)a[++len] = n % 10, n /= 10; int res = 0; for (int i = 1;i <= len * 9;++i) { mod = i;memset(f, -1, sizeof f); res += dfs(len, 0, 0, 1, 1); } cout << res; return0; }