深知自己DP很弱,昨天被POJ上的一道DP题卡了一个晚上,而且是想不出来状态,写不出来方程的卡住。TAT
所以来写一道水一点的找找自信。
![哭](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
说水也不水,因为我一开始想的状态是f[i][c1][c2][c3][c4]表示在第i个格子,第i种卡牌剩ci张时所得的分数,状态转移就是f[i][c1][c2][c3][c4] = max(f[i-1][c1+1][c2][c3][c4], f[i-2][c1][c2+1][c3][c4]……)+s[i];不过很显然这个会爆内存。
不过我们可以想到,因为保证4种卡牌用完时是走到终点的,也就是说当前在哪个点,可以又四种卡牌剩余量推得,为了方便,可以改成ci表示第i种卡牌用了ci张。
那么状态转移就是f[c1][c2][c3][c4] = max(f[c1-1][c2][c3][c4], f[c1][c2-2][c3][c4], f[c1][c2][c3-1][c4], f[c1][c2][c3][c4-1])+s[1+c1+c2*2+c3*3+c4*4]. 边界f[0][0][0][0] = s[1].
#include <cstdio>
#include <algorithm>
using namespace std;
int n, m, s[355], f[45][45][45][45], t, c[5];
int main()
{
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; i++)
scanf("%d", s+i);
for(int i = 1; i <= m; i++){
scanf("%d", &t);
c[t]++;
}
f[0][0][0][0] = s[1];
for(int c1 = 0; c1 <= c[1]; c1++)
for(int c2 = 0; c2 <= c[2]; c2++)
for(int c3 = 0; c3 <= c[3]; c3++)
for(int c4 = 0; c4 <= c[4]; c4++){
if(c1-1>=0)
f[c1][c2][c3][c4] = max(
f[c1-1][c2][c3][c4]+s[1+c1+c2*2+c3*3+c4*4],
f[c1][c2][c3][c4]);
if(c2-1>=0)
f[c1][c2][c3][c4] = max(
f[c1][c2-1][c3][c4]+s[1+c1+c2*2+c3*3+c4*4],
f[c1][c2][c3][c4]);
if(c3-1>=0)
f[c1][c2][c3][c4] = max(
f[c1][c2][c3-1][c4]+s[1+c1+c2*2+c3*3+c4*4],
f[c1][c2][c3][c4]);
if(c4-1>=0)
f[c1][c2][c3][c4] = max(
f[c1][c2][c3][c4-1]+s[1+c1+c2*2+c3*3+c4*4],
f[c1][c2][c3][c4]);
}
printf("%d", f[c[1]][c[2]][c[3]][c[4]]);
}