一看就知道是 dp 题,但是我太弱了,只会记忆化搜索。
为了方便搜索,我们在输入数据后初始化一个二维数组 d d d, d i , j d_{i,j} di,j 表示在 Ivan 送给 Nikola j j j 张第 i i i 支足球队的照片时,第 i i i 支足球队的得分。
for(int i=1;i<=n;i++) {
d[i][0]=B[P[i]];
for(int j=1;j<=m-P[i];j++) {
d[i][j]=B[P[i]+j];
}
d[i][m-P[i]+1]=-1;
}
然后准备搜索。
for(int i=0;i<=k;i++){
for(int j=0;j<=n;j++){
F[i][j]=-1; //-1表示还没搜过
}
}
递归函数 f ( k , n ) f(k,n) f(k,n) 返回在 Ivan 送 k k k 张照片给 Nikola,只考虑前 n n n 个球队时能够得到的分数的最大值,那么(详细看注释):
int f(int k, int n) {
if(n==0)
return 0;
if(F[k][n]!=-1)
return F[k][n];
int rs = 0;
for(int i=0;d[n][i]!=-1 && i<=k;i++) {
rs = max(rs, f(k-i, n-1)+d[n][i]);
}
F[k][n] = rs;//记忆化
return rs;
}
很明显,
f
(
K
,
N
)
f(K, N)
f(K,N) 就是最终的答案。
时间复杂度:
O
(
N
K
2
)
O(NK^2)
O(NK2)
完整代码:
#include<bits/stdc++.h>
using namespace std;
int P[600],B[600];
int n,m;
int d[600][600];
int F[600][600];
int f(int k,int n)
if(n==0)
return 0;
if(F[k][n]!=-1)
return F[k][n];
int rs=0;
for(int i=0;d[n][i]!=-1&&i<=k;i++)
rs=max(rs,f(k-i,n-1)+d[n][i]);
}
F[k][n]=rs;
return rs;
}
int main() {
int k;
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++){
scanf("%d",&P[i]);
}
for(int i=0;i<=m;i++){
scanf("%d",&B[i]);
}
for(int i=1;i<=n;i++){
d[i][0]=B[P[i]];
for(int j=1;j<=m-P[i];j++){
d[i][j]=B[P[i]+j];
}
d[i][m-P[i]+1]=-1;
}
for(int i=0;i<=k;i++){
for(int j=0;j<=n;j++){
F[i][j]=-1;
}
}
printf("%d",f(k, n));
}