#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
#define now d[i]
const int maxg = 210;
int p[maxg][maxg], d[maxg], f[2][6][6][6][6], b[maxg][maxg], n, m, g, T;
struct Node
{
int id, x;
bool operator < (const Node &oth) const
{
return x > oth.x;
}
};
Node t[maxg];
void dp()
{
memset(f, -1, sizeof(f));
f[0][0][0][0][0] = 0;
int coin = 0, ans = 0;
int wj = -10, wk = -10, wl = -10, wq = -10;
for (int i = 1; i <= g + 10; i++)
if (d[i] != 0)
{
ans = 0;
memset(f[!coin], -1, sizeof(f[!coin]));
for (int j = 0; j <= 5; j++)
for (int k = 0; k <= 5; k++)
for (int l = 0; l <= 5; l++)
for (int q = 0; q <= 5; q++)
if (f[coin][j][k][l][q] != -1)
for (int id = 1; id <= 5; id++)
{
if ((i - wj <= 4 && b[now][id] == b[d[wj]][j]) || (i - wk <= 4 && b[now][id] == b[d[wk]][k]) ||
(i - wl <= 4 && b[now][id] == b[d[wl]][l]) || (i - wq <= 4 && b[now][id] == b[d[wq]][q])) continue;
f[!coin][k][l][q][id] =
max(f[!coin][k][l][q][id], f[coin][j][k][l][q] + p[now][b[now][id]]);
ans = max(ans, f[!coin][k][l][q][id]);
}
wj = wk; wk = wl; wl = wq; wq = i, coin = !coin;
}
printf("%.2lf\n", ans * 1.0 / 100);
}
int main(int argc, char const *argv[])
{
scanf("%d", &T);
while (T--)
{
scanf("%d%d%d", &n, &m, &g);
for (int i = 1; i <= m; i++)
for (int j = 1; j <= n; j++)
scanf("%d", &p[i][j]);
for (int i = 1; i <= g + 10; i++)
scanf("%d", &d[i]);
memset(b, 0, sizeof(b));
for (int i = 1; i <= m; i++)
{
for (int j = 1; j <= n; j++)
t[j].id = j, t[j].x = p[i][j];
sort(t + 1, t + 1 + n);
for (int j = 1; j <= 5; j++)
b[i][j] = t[j].id;
}
dp();
}
return 0;
}
直接记录前4天中每天上场的投手编号1~n,时间和空间都无法承受。但是,不记录又不行。因为规定一个投手在上场一次后至少要休息4天,也就是说记录前4天的作战计划是必要的,但是我们可以简化这个编号的范围。在这里用到了贪心的思想,对于第i天,我们只会选择当天能力值前5的投手出战。所以记录的时候,只需记录你选的是当天排名第几的投手,然后判断选择不同于前4天的投手DP即可。