NOIP2010提高组 T2. 乌龟棋(多线程DP)

题目:

小明过生日的时候,爸爸送给他一副乌龟棋当作礼物。

乌龟棋的棋盘只有一行,该行有 N 个格子,每个格子上一个分数(非负整数)。

棋盘第 1 格是唯一的起点,第 N 格是终点,游戏要求玩家控制一个乌龟棋子从起点出发走到终点。

乌龟棋中共有 M 张爬行卡片,分成 4 种不同的类型(M 张卡片中不一定包含所有 4 种类型的卡片),每种类型的卡片上分别标有1、2、3、4 四个数字之一,表示使用这种卡片后,乌龟棋子将向前爬行相应的格子数。

游戏中,玩家每次需要从所有的爬行卡片中选择一张之前没有使用过的爬行卡片,控制乌龟棋子前进相应的格子数,每张卡片只能使用一次。

游戏中,乌龟棋子自动获得起点格子的分数,并且在后续的爬行中每到达一个格子,就得到该格子相应的分数。

玩家最终游戏得分就是乌龟棋子从起点到终点过程中到过的所有格子的分数总和。

很明显,用不同的爬行卡片使用顺序会使得最终游戏的得分不同,小明想要找到一种卡片使用顺序使得最终游戏得分最多。

现在,告诉你棋盘上每个格子的分数和所有的爬行卡片,你能告诉小明,他最多能得到多少分吗?

输入格式
输入文件的每行中两个数之间用一个空格隔开。

第 1 行 2 个正整数 N 和 M,分别表示棋盘格子数和爬行卡片数。

第 2 行 N 个非负整数,a1,a2,……,aN,其中 ai 表示棋盘第 i 个格子上的分数。

第 3 行 M 个整数,b1,b2,……,bM,表示 M 张爬行卡片上的数字。

输入数据保证到达终点时刚好用光 M 张爬行卡片。

输出格式
输出只有 1 行,包含 1 个整数,表示小明最多能得到的分数。

数据范围
1 ≤ N ≤ 350,
1 ≤ M ≤ 120,
0 ≤ ai ≤ 100,
1 ≤ bi ≤ 4,
每种爬行卡片的张数不会超过40。

输入样例:
9 5
6 10 14 2 8 8 18 5 17
1 3 1 2 1
输出样例:
73

  • 题解:这道题与之前NOIP中的方格取数有点类似,一样用到多线程DP的思想进行解题,因为有四种卡片,所以将每一次选择可能存在四种状态,那么需要利用四维空间对数据进行存储.
  • 集合表示:f[i][j][k][h]表示使用i张a类卡片,j张b类卡片,k张c类卡片,h张d类卡片所构成的爬行方案所得到的最大分数
  • 状态转移方程:
    1. 选择一张a类卡片,那么所爬行所获得的分数肯定是f[i-1][j][k][h] + x[i][j * 2][k * 3][h * 4](当前所在位置的分数)
    2. 选择一张b类卡片,那么所爬行所获得的分数肯定是f[i][j-1][k][h] + x[i][j * 2][k * 3][h * 4](当前所在位置的分数)
    3. 选择一张c类卡片,那么所爬行所获得的分数肯定是f[i][j][k-1][h] + x[i][j * 2][k * 3][h * 4](当前所在位置的分数)
    4. 选择一张a类卡片,那么所爬行所获得的分数肯定是f[i][j][k][h-1] + x[i][j * 2][k * 3][h * 4](当前所在位置的分数)
    5. 取四种情况的最大值即为最终f[i][j][k][h]的答案
  • 最后结果即为:f[a][b][c][d](a、b、c、d分别代表四类卡片数量)
  • 代码:
#include<iostream>
using namespace std;
const int N = 355;
const int M = 45;
int a, b, c, d;
int f[M][M][M][M], x[N];
int n, m;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    cin >> n >> m;
    for(int i = 0; i < n; i++)
        cin >> x[i];
    f[0][0][0][0] =  x[0]; //起点不需要卡片可自动获得分数
    for(int i = 1; i <= m; i++)
    {
        int t;
        cin >> t;
        if(t == 1) a ++;
        else if(t == 2) b ++;
        else if(t == 3) c ++;
        else if(t == 4) d ++;
    }
    for(int i = 0; i <= a; i++)
    {
        for(int j = 0; j <= b; j++)
        {
            for(int k = 0; k <= c; k++)
            {
                for(int h = 0; h <= d; h++)
                {
                        if(i >= 1) //防止数组越界
                            f[i][j][k][h] = max(f[i][j][k][h], f[i-1][j][k][h] + x[i+j*2+k*3+h*4]);
                        if(j >= 1)
                            f[i][j][k][h] = max(f[i][j][k][h], f[i][j-1][k][h] + x[i+j*2+k*3+h*4]);
                        if(k >= 1)
                            f[i][j][k][h] = max(f[i][j][k][h], f[i][j][k-1][h] + x[i+j*2+k*3+h*4]);
                        if(h >= 1)
                            f[i][j][k][h] = max(f[i][j][k][h], f[i][j][k][h-1] + x[i+j*2+k*3+h*4]);
                }
            }
        }
    }
    cout << f[a][b][c][d];
    return 0;
}
posted @ 2021-02-23 11:17  ~K2MnO4  阅读(154)  评论(0)    收藏  举报