乌龟棋(线性dp)

前言

乌龟棋是NOIP2010提高组的原题,是一类典型线性dp的代表题目。

题意

给定 n n n个数,从左边开始走到右边。共有 m m m张卡片,分成 4 4 4种不同的类型,每种类型的卡片上分别标有 1 、 2 、 3 、 4 1、2、3、4 1234四个数字之一,表示使用这种卡片后,将向前行走相应的格子数。每次走到哪个格子,就会获得对应的数字,问走到最后,获得数字总和最大为多少。

数据范围

1 ≤ m ≤ 350 1 \leq m \leq 350 1m350
1 ≤ n ≤ 120 1 \leq n \leq 120 1n120
每种卡片最多有 40 40 40张。

思路

f ( i , j , k , l ) f(i,j,k,l) f(i,j,k,l)表示四种卡片分别使用了若干张的走法的最大值。
按最后一步选择哪张卡片分成四类,以第一类卡片为例,若最后一步为 1 1 1,则前一个状态为 f ( i − 1 , j , k , l ) f(i - 1,j,k,l) f(i1,j,k,l)
状态转移方程为, f ( i , j , k , l ) = m a x ( f ( i , j , k , l ) , f ( i − 1 , j , k , l ) + a [ i + j ∗ 2 + k ∗ 3 + l ∗ 4 ] ) f(i,j,k,l) = max(f(i,j,k,l),f(i-1,j,k,l) + a[i+j*2+k*3+l*4]) f(i,j,k,l)=max(f(i,j,k,l),f(i1,j,k,l)+a[i+j2+k3+l4])

代码

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

const int N = 360, M = 45;

int n, m;
int a[N];
int f[M][M][M][M];

int main()
{
    
    
    int b[5] = {
    
    0};
    cin >> n >> m;
    for(int i=0;i<n;i++) cin >> a[i];
    for(int i=1;i<=m;i++){
    
    
        int x;
        cin >> x;
        b[x] ++;
    }
    for(int i=0;i<=b[1];i++)
        for(int j=0;j<=b[2];j++)
            for(int k=0;k<=b[3];k++)
                for(int l=0;l<=b[4];l++)
                {
    
    
                    int tot = a[i+j*2+k*3+l*4];
                    f[i][j][k][l] = tot;
                    if(i) f[i][j][k][l] = max(f[i][j][k][l], f[i-1][j][k][l]+tot);
                    if(j) f[i][j][k][l] = max(f[i][j][k][l], f[i][j-1][k][l]+tot);
                    if(k) f[i][j][k][l] = max(f[i][j][k][l], f[i][j][k-1][l]+tot);
                    if(l) f[i][j][k][l] = max(f[i][j][k][l], f[i][j][k][l-1]+tot);
                }
    
    cout << f[b[1]][b[2]][b[3]][b[4]] << endl;;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43634220/article/details/108457354
今日推荐