不会被调用到的状或者没有实际意义的状态,不会被调用到,就不会影响最终的结果,但在最终收集结果要避免它。
本题,看上去没有好办法,直接dp空间时间都受不了,可以先排序对阵每个对手的一行,则该行会被用到的会是前几个,但我不确定一定是前5个,但这样去做,就A了,有待证明。
本题有些特殊状态即前4天的状态,因为如第三天,在计算他的最优值是,只有他的前两天有参考价值,那么只参考前两个维度,d[ 3 ][ 1 ] [ 2 ] [ ] [ ]都是一个状态。
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
using namespace std;
const int maxn = 110;
const int maxg = 240;
int dp[2][6][6][6][6],n,m,g,b[maxg];
#define rep(i,n) for(int i=0;i<n;i++)
int cmax(int& a,int b){
if(a<b) a = b;
}
struct node{
int v,id;
node(int x=0,int y=0):v(x),id(y){}
bool operator <(const node& rhs)const{
return v>rhs.v;
}
}a[110][maxn];
int main()
{
for(int i=0;i<35;i++) a[i][0]=node(0,0);
for(int i=0;i<100;i++) a[0][i]=node(0,0);
int T;
scanf("%d",&T);
while(T--){
scanf("%d %d %d",&n,&m,&g);
g+=10;
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
scanf("%d",&a[i][j].v);
a[i][j].id = j;
}
sort(a[i]+1,a[i]+1+n);
}
for(int i=1;i<=g;i++) scanf("%d",&b[i]);
int pre = 0,now = 1;
memset(dp,0,sizeof(dp));
for(int i=g;i>=1;i--){
memset(dp[now],0,sizeof(dp[now]));
rep(j,6)
rep(k,6)
rep(l,6)
rep(r,6){
int p = b[i];
if(!p) cmax(dp[now][j][k][l][r],dp[pre][0][j][k][l]);
else
for(int s=1;s<=5;s++){
if(a[p][s].id){
if(i-1>0&&a[p][s].id==a[b[i-1]][j].id) continue;
if(i-2>0&&a[p][s].id==a[b[i-2]][k].id) continue;
if(i-3>0&&a[p][s].id==a[b[i-3]][l].id) continue;
if(i-4>0&&a[p][s].id==a[b[i-4]][r].id) continue;
}
cmax(dp[now][j][k][l][r],dp[pre][s][j][k][l]+a[p][s].v);
}
}
pre^=1; now^=1;
}
int res = 0;
rep(j,6)
rep(k,6)
rep(l,6)
rep(r,6){
res = max(res,dp[pre][j][k][l][r]);
}
cout<<(res/(100.0))<<endl;
}
return 0;
}