给定一个长度为 m m m 的整数序列 a 1 , a 2 , … , a m a_1,a_2,…,a_m a1,a2,…,am。
序列中每个元素的值 a i a_i ai 均满足 1 ≤ a i ≤ n 1≤a_i≤n 1≤ai≤n。
当一个值为 i i i 的元素和一个值为 j j j 的元素相邻时,可以产生的收益为 w i , j w_{i,j} wi,j。
现在,我们可以从序列中删除最多 k k k 个元素,删除一些元素后,原本不相邻的元素可能会变得相邻。
序列的收益和为所有相邻元素对产生的收益之和,例如一个长度为 3 3 3 的整数序列 1 , 3 , 2 1,3,2 1,3,2 的收益和为 w 1 , 3 + w 3 , 2 w_{1,3}+w_{3,2} w1,3+w3,2。
请问,通过利用删除操作,能够得到的序列的最大收益和是多少?
输入格式
第一行包含三个整数
n
,
k
,
m
n,k,m
n,k,m。
第二行包含 m m m 个整数 a 1 , a 2 , … , a m a_1,a_2,…,a_m a1,a2,…,am。
接下来 n n n 行,每行包含 n n n 个整数,其中第 i i i 行第 j j j 列的数表示 w i , j w_{i,j} wi,j。
输出格式
输出序列的最大收益和。
数据范围
对于 30% 的数据,
1
≤
n
,
k
,
m
≤
20
1≤n,k,m≤20
1≤n,k,m≤20。
对于 100% 的数据,
1
≤
n
,
k
,
m
≤
200
,
0
≤
w
i
,
j
≤
1
0
7
,
1
≤
a
i
≤
n
1≤n,k,m≤200,0≤w_{i,j}≤10^7,1≤a_i≤n
1≤n,k,m≤200,0≤wi,j≤107,1≤ai≤n。
数据保证
w
i
,
j
=
w
j
,
i
,
w
i
,
i
=
0
w_{i,j}=w_{j,i},w_{i,i}=0
wi,j=wj,i,wi,i=0。
输入样例:
4 1 3
1 4 2
0 3 0 1
3 0 0 0
0 0 0 0
1 0 0 0
输出样例:
3
样例解释
初始序列收益和为
w
1
,
4
+
w
4
,
2
=
1
+
0
=
1
w_{1,4}+w_{4,2}=1+0=1
w1,4+w4,2=1+0=1。
删除中间的 4 4 4 后,序列 1 , 2 1,2 1,2 的收益和为 w 1 , 2 = 3 w_{1,2}=3 w1,2=3。
状态表示 f [ i ] [ j ] f[i][j] f[i][j]
状态计算
#include
#include
using namespace std;
const int N = 210;
int n, k, m;
int a[N], w[N][N], f[N][N];
int main(){
memset(f, -0x3f, sizeof f);
scanf("%d%d%d", &n, &k, &m);
for(int i = 1; i <= m; i++) scanf("%d", &a[i]);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
scanf("%d", &w[i][j]);
f[1][0] = 0;
for(int i = 2; i <= m; i++)
for(int j = 0; j <= k; j++)
for(int u = 1; u < i; u++)
if(j >= i - u - 1)
f[i][j] = max(f[i][j], f[u][j-(i-u-1)]+w[a[u]][a[i]]);
int res = 0;
for(int i = 0; i <= k; i++)
res = max(res, f[m][i]);
printf("%d\n", res);
return 0;
}