http://codevs.cn/problem/1068/
我的做法是用四维数组dp[50][50][50][50],dp[a][b][c][d]记录的是当剩下a个一的卡片,b个二的卡片,c个三的卡片,d个四的卡片时,最大的得分。
用vector维护到达每个点时的所有状态,所以我这个做法是完全暴力的做法优化而来的。看代码
#include<bits/stdc++.h>
#define pb push_back
using namespace std;
const int maxn = 350;
struct node
{
int a,b,c,d;
int ans;
}ok;
vector<node>V[maxn];
int s[maxn],b[5],dp[40][40][40][40];
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
for(int i=0;i<n;i++) V[i].clear();
for(int i=0;i<n;i++) scanf("%d",&s[i]);
memset(b,0,sizeof(b));
for(int i=1;i<=m;i++)
{
scanf("%d",&b[0]);
b[b[0]]++;
}
memset(dp,-1,sizeof(dp));
ok.ans = s[0],ok.a = b[1],ok.b = b[2],ok.c = b[3],ok.d = b[4];
V[0].pb(ok);
dp[b[1]][b[2]][b[3]][b[4]] = s[0];
for(int i=1;i<n;i++)
{
for(int j=1;j<=4 && i-j>=0;j++)
{
for(int k=0;k<V[i-j].size();k++)
{
ok = V[i-j][k];
if(j==1 && ok.a<=0 ) continue;
if(j==2 && ok.b<=0 ) continue;
if(j==3 && ok.c<=0 ) continue;
if(j==4 && ok.d<=0 ) continue;
if(dp[ok.a][ok.b][ok.c][ok.d]<=ok.ans)
{
switch(j)
{
case 1:ok.a--;break;
case 2:ok.b--;break;
case 3:ok.c--;break;
case 4:ok.d--;break;
}
ok.ans+=s[i];
if(dp[ok.a][ok.b][ok.c][ok.d]<ok.ans)
{
V[i].pb(ok);
dp[ok.a][ok.b][ok.c][ok.d]=ok.ans;
}
}
}
}
}
printf("%d\n",dp[0][0][0][0]);
}
return 0;
}
后来知道网上有种非常暴力的,直接枚举所有a,b,c,d四种卡片,那种做法比我的快多了。 我怎么就没想到呢!!!!