P1541 [NOIP2010 提高组] 乌龟棋
没思路?可以先写个 dfs 看看
#include <bits/stdc++.h>
using namespace std;
int n, m, ans;
int a[400], b[150];
bool used[150];
void dfs(int i, int sum){
if(i >= n){
ans = max(ans, sum);
return;
}
for(int j = 1; j <= m; ++j){
if(!used[j]){
used[j] = 1;
dfs(i + b[j], sum + a[i + b[j]]);
used[j] = 0;
}
}
}
int main(){
scanf("%d%d" ,&n ,&m);
for(int i = 1; i <= n; ++i){
scanf("%d" ,&a[i]);
}
for(int i = 1; i <= m; ++i){
scanf("%d" ,&b[i]);
}
dfs(1, a[1]);
printf("%d" ,ans);
return 0;
}
由此我们可以确定状态:
- i i i ,表示位置
- s u m sum sum ,表示和
然而, 状态仅仅有两个么?
事实上 u s e d used used 也是一个状态 , 用来表示是否使用过某个爬行卡片, 但是我们一般不会把它写到 dfs 函数的参数里.所以我们把它写在了外面.
然而,我们如果想写出 DP , 就应该把所有状态都放进数组的下标里. DP 是不能回溯的,肯定不能模仿 dfs 中的写法.我们必须找出另一种可能的方法来表示是否使用过的状态.
且4种爬行卡片,每种卡片的张数不会超过40
我们发现,所有的爬行卡片都只有4种类型,所以 u s e d used used 可以用四种类型的卡片分别使用过的数量来替代.而所有类型的卡片最大数量是确定的,所以可以用数组存下来了.
设使用的 1 , 2 , 3 , 4 1,2,3,4 1,2,3,4 类型的爬行卡片数量分别为 i 1 , i 2 , i 3 , i 4 i_1, i_2, i_3, i_4 i1,i2,i3,i4 , 当前位置为 i d id id ,那么当前取得的和 s u m sum sum 可表示为 d p [ i 1 ] [ i 2 ] [ i 3 ] [ i 4 ] [ i d ] dp[i_1][i_2][i_3][i_4][id] dp[i1][i2][i3][i4][id] ,至此所有状态就可以表示出来了.
但是我们发现一个问题
对于 100 % 100\% 100% 的数据有 1 ≤ N ≤ 350 , 1 ≤ M ≤ 120 1≤N≤350,1≤M≤120 1≤N≤350,1≤M≤120
我们需要开的数组大小至少为 d p [ 40 ] [ 40 ] [ 40 ] [ 40 ] [ 350 ] dp[40][40][40][40][350] dp[40<