题目大意
有 n n n 头奶牛,第 i i i 头奶牛有智商 a i a_i ai 和情商 b i b_i bi。从中任选若干头奶牛,使得他们的智商之和、情商之和均不为负数,且智商与情商之和最大。 n ≤ 400 , ∣ a i , b i ∣ ≤ 1000 n≤400,|a_i,b_i|≤1000 n≤400,∣ai,bi∣≤1000.
解题思路
设
f
[
i
]
[
j
]
f[i][j]
f[i][j] 表示使用前
i
i
i 头奶牛,且他们的智商之和为
i
i
i 的最优解。则
f
[
i
]
[
j
]
=
max
k
<
i
{
f
[
k
]
[
j
−
a
[
k
]
]
+
a
[
k
]
+
b
[
k
]
}
f[i][j]=\max_{k<i}\{f[k][j-a[k]]+a[k]+b[k]\}
f[i][j]=k<imax{f[k][j−a[k]]+a[k]+b[k]}
注意到每次只需要令
k
=
i
−
1
k=i-1
k=i−1 即可,于是空间压缩为一维。时间复杂度
O
(
n
∣
a
∣
2
)
O(n|a|^2)
O(n∣a∣2),空间复杂度
O
(
n
∣
a
∣
)
O(n|a|)
O(n∣a∣)。
本题卡常数,请开O2。
#include <cstdio>
#include <cstdlib>
#include <cstring>
const int MAXN=410;
const int delta=400000;
int n;
int a[MAXN], b[MAXN];
int f[3][delta*2+20];
#define max(x,y) ((x)>(y)?(x):(y))
int main (){
scanf ("%d", &n);
for (int i=1; i<=n; ++i)
scanf ("%d%d", &a[i], &b[i]);
memset (f, -63, sizeof (f)); f[1][delta]=0;
for (int i=1; i<=n; ++i){
for (int j=0; j<=delta*2; ++j)
f[0][j]=f[1][j];
for (int j=0; j<=delta*2; ++j){
if (j<a[i]) continue;
f[1][j]=max (f[1][j], f[0][j-a[i]]+b[i]);
}
}
int ans=0;
for (int i=delta; i<=delta*2; ++i)
if (0<=f[1][i])
ans=max (ans, f[1][i]+i-delta);
printf ("%d", ans);
}