前言:
做该题时,困在了状态转移方程中,总结出一个新知识:
状态转移时,需要遍历每一种状态。但设计状态转移方程时,只需要考虑当前状态由哪些状态转移得到即可。
思路:动态规划
定义状态:dp[i][j][k][l],即使用i,j,k,l张第1,2,3,4种卡牌的最高得分。
状态转移:对于状态[i][j][k][l], 可能是最后使用了第1类卡牌得到,也可能是最后使用了第二类卡牌得到,也可能是第3类或者第四类。一共就这三种情况,状态转移方程如下:
dp[p1][p2][p3][p4] = Math.max(dp[p1][p2][p3][p4], dp[p1-1][p2][p3][p4]+a[cur]);
dp[p1][p2][p3][p4] = Math.max(dp[p1][p2][p3][p4], dp[p1][p2-1][p3][p4]+a[cur]);
dp[p1][p2][p3][p4] = Math.max(dp[p1][p2][p3][p4], dp[p1][p2][p3-1][p4]+a[cur]);
dp[p1][p2][p3][p4] = Math.max(dp[p1][p2][p3][p4], dp[p1][p2][p3][p4-1]+a[cur]);
其中a[cur]表示使用了p1,p2,p3,p4卡牌的最后位置,这个位置是固定的。
代码
int n,m;
int[] a = new int[400];
int[] cnt = new int[5];
int[][][][] dp = new int[41][41][41][41];
void test() throws IOException {
Reader cin = new Reader();
n = cin.nextInt();
m = cin.nextInt();
for(int i = 1; i <= n; i++) a[i] = cin.nextInt();
for(int i = 1; i <= m; i++) cnt[cin.nextInt()]++;
dp[0][0][0][0] = a[1];
for(int p1 = 0; p1 <= cnt[1]; p1++) {
for(int p2 = 0; p2 <= cnt[2]; p2++) {
for(int p3 = 0; p3 <= cnt[3]; p3++) {
for(int p4 = 0; p4 <= cnt[4]; p4++) {
int cur = 1+p1+2*p2+3*p3+4*p4;
if(p1 > 0) dp[p1][p2][p3][p4] = Math.max(dp[p1][p2][p3][p4], dp[p1-1][p2][p3][p4]+a[cur]);
if(p2 > 0) dp[p1][p2][p3][p4] = Math.max(dp[p1][p2][p3][p4], dp[p1][p2-1][p3][p4]+a[cur]);
if(p3 > 0) dp[p1][p2][p3][p4] = Math.max(dp[p1][p2][p3][p4], dp[p1][p2][p3-1][p4]+a[cur]);
if(p4 > 0) dp[p1][p2][p3][p4] = Math.max(dp[p1][p2][p3][p4], dp[p1][p2][p3][p4-1]+a[cur]);
}
}
}
}
System.out.println(dp[cnt[1]][cnt[2]][cnt[3]][cnt[4]]);
}