动态规划中状态与含义的适当转换
Claire0918 · · 算法·理论
例题:AT_dp_e。
正常的背包中我们记
#include<bits/stdc++.h>
#define mem(a, v) memset(a, v, sizeof(a))
using namespace std;
const int maxn = 100 + 10, maxv = 1e3;
int n, m;
int a[maxn], b[maxn], f[maxn * maxv];
int main(){
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++){
scanf("%d %d", &a[i], &b[i]);
}
mem(f, 0x3f), f[0] = 0;
for (int i = 1; i <= n; i++){
for (int j = i * maxv; j >= b[i]; j--){
f[j] = min(f[j], f[j - b[i]] + a[i] <= m ? f[j - b[i]] + a[i] : m + 1);
}
}
for (int i = n * maxv; ~i; i--){
if (f[i] <= m){
printf("%d", i);
return 0;
}
}
return 0;
}
通过上面的例子,我们发现可以将 DP 中的所有状态和含义放进一个集合(如上文中是
应用:Union2024 S1178。
题目允许将
取得最小值,即
取得最大值。
设
我们注意到
#include<bits/stdc++.h>
#define mem(a, v) memset(a, v, sizeof(a))
using namespace std;
const int maxm = 100 + 10, maxk = 100;
int m, q;
int a[maxm];
long long f[maxk + 10][maxk * maxm];
int main(){
freopen("run.in", "r", stdin);
freopen("run.out", "w", stdout);
scanf("%d", &m);
for (int i = 1; i <= m; i++){
scanf("%d", &a[i]);
}
sort(a + 1, a + m + 1);
mem(f, 0x3f), f[0][0] = 0;
for (int i = 1; i <= maxk; i++){
for (int j = 0; j <= i * m; j++){
for (int k = 0; k <= m && k <= j; k++){
f[i][j] = min(f[i][j], f[i - 1][j - k] + a[k]);
}
}
}
scanf("%d", &q);
while (q--){
int n, k;
scanf("%d %d", &n, &k);
int l = 0, r = k * m;
while (l < r){
const int mid = l + r + 1 >> 1;
if (f[k][mid] <= n){
l = mid;
}else{
r = mid - 1;
}
}
printf("%d\n", n - l);
}
return 0;
}