题目链接:点击这里
题目大意:
有一个数轴,每个位置有一个权值,人一开始在
1
1
1 的位置,有分别标有
1
,
2
,
3
,
4
1,2,3,4
1,2,3,4 的四种牌,每种牌可以让人走相应的步数,且每张牌只能用一次,求使用给出的
m
m
m 张牌能走到的最大权值和
题目分析:
无后效性最优化问题,考虑
d
p
dp
dp
设状态
d
p
[
i
]
[
j
]
[
k
]
[
x
]
dp[i][j][k][x]
dp[i][j][k][x] 表示
1
,
2
,
3
,
4
1,2,3,4
1,2,3,4 四种牌分别用了
i
,
j
,
k
,
x
i,j,k,x
i,j,k,x 张的最大权值和
初始状态为
d
p
[
0
]
[
0
]
[
0
]
[
0
]
=
a
[
1
]
dp[0][0][0][0]=a[1]
dp[0][0][0][0]=a[1]
转移方程就是抉择每种卡片用与不用:
d
p
[
i
]
[
j
]
[
k
]
[
x
]
=
d
p
[
i
−
1
]
[
j
]
[
k
]
[
x
]
+
a
[
p
o
s
]
dp[i][j][k][x]=dp[i-1][j][k][x]+a[pos]
dp[i][j][k][x]=dp[i−1][j][k][x]+a[pos] ,其中
p
o
s
=
1
+
i
+
2
j
+
3
k
+
4
x
pos=1+i+2j+3k+4x
pos=1+i+2j+3k+4x ,其余
j
,
k
,
x
j,k,x
j,k,x 的转移同理
具体细节见代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<set>
#include<map>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
int read()
{
int res = 0,flag = 1;
char ch = getchar();
while(ch<'0' || ch>'9')
{
if(ch == '-') flag = -1;
ch = getchar();
}
while(ch>='0' && ch<='9')
{
res = (res<<3)+(res<<1)+(ch^48);//res*10+ch-'0';
ch = getchar();
}
return res*flag;
}
const int maxn = 350+5;
const int mod = 1e9+7;
const double pi = acos(-1);
const double eps = 1e-8;
int n,m,a[maxn],cnt[5],dp[45][45][45][45];
int main()
{
n = read(),m = read();
for(int i = 1;i <= n;i++)
a[i] = read();
for(int i = 1;i <= m;i++)
cnt[read()]++;
dp[0][0][0][0] = a[1];
for(int i = 0;i <= cnt[1];i++)
for(int j = 0;j <= cnt[2];j++)
for(int k = 0;k <= cnt[3];k++)
for(int x = 0;x <= cnt[4];x++)
{
int pos = 1+i+2*j+3*k+4*x;
if(i) dp[i][j][k][x] = max(dp[i][j][k][x],dp[i-1][j][k][x]+a[pos]);
if(j) dp[i][j][k][x] = max(dp[i][j][k][x],dp[i][j-1][k][x]+a[pos]);
if(k) dp[i][j][k][x] = max(dp[i][j][k][x],dp[i][j][k-1][x]+a[pos]);
if(x) dp[i][j][k][x] = max(dp[i][j][k][x],dp[i][j][k][x-1]+a[pos]);
}
printf("%d\n",dp[cnt[1]][cnt[2]][cnt[3]][cnt[4]]);
return 0;
}