zoukankan      html  css  js  c++  java
  • 【动态规划】P1541 乌龟棋

    https://www.luogu.com.cn/problem/P1541

    P1541 乌龟棋【NOIp提高组2010】【普及+/提高】 题解

    这是一道dp题目。关于dp题,在设计状态的时候,要想清楚在整个状态空间中发生变化的量有哪些。

    对于这个题目,我们可以找到以下的“变量”:

    1.棋子所在的位置;

    2.所用的各个种类的牌的数量。(实际上算4个变量)

    于是我们很容易想到使用五维数组 f [ i ][ a ][ b ][ c ][ d ] 来表示:走到第 i 个格子,用了标有数字 1~4 的卡牌分别有 a,b,c,d 张,所得到的最大分数。

    我们还可以继续优化。很明显,如果a,b,c,d都知道的话,i 是可以推出来的,即1+a+2b+3c+4d(由于本来棋子就在第1格,所以要加1)。这时 i 叫做“冗余状态",可以省去,用 f [ a ][ b ][ c ][ d ] 表示用了标有数字 1~4 的卡牌分别有 a,b,c,d 张,能得到的最大分数。

    状态转移:由于f [ a ][ b ][ c ][ d ]可以由f [ a-1 ][ b ][ c ][ d ],f [ a ][ b-1 ][ c ][ d ],f [ a ][ b ][ c-1 ][ d ]和f [ a ][ b ][ c ][ d-1 ]转移而来,再加上 k [ 1+a+2b+3c+4d ]即可。其中 k [ i ] 表示第 i 个格子的分数。上述所有条件取一个最大值即可。注意 a,b,c,d 均不能超过题目中所给的每种卡牌对应的数量。

    初始状态:f [ 0 ][ 0 ][ 0 ][ 0 ] = k[ 1 ]。因为乌龟棋本来就在第一个格子上。

    目标:f [ am ] [ b][ c][ d] 。其中 a表示 标有数字1的卡牌的数量,其他的以此类推。

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #define MAXN 1001
    #define ll long long
    #define re register
    using namespace std;
    int card[5];
    inline int get_i(int a,int b,int c,int d)
    {
        return 1+a+b*2+c*3+d*4;
    }
    int n,m;
    int k[MAXN];
    int f[41][41][41][41];
    int main()
    {
        ios::sync_with_stdio(false);
        cin>>n>>m;
        for(int i=1;i<=n;i++)
        {
            cin>>k[i];
        }
        int tmp;
        for(int i=1;i<=m;i++)
        {
            cin>>tmp;
            card[tmp]++;
        } 
        //dp
        f[0][0][0][0]=k[1];
        for(int a=0;a<=card[1];a++)
        {
            for(int b=0;b<=card[2];b++)
            {
                for(int c=0;c<=card[3];c++)
                {
                    for(int d=0;d<=card[4];d++)
                    {
                        int now=get_i(a,b,c,d);
                        if(a!=0) f[a][b][c][d]=max(f[a][b][c][d],f[a-1][b][c][d]+k[now]);
                        if(b!=0) f[a][b][c][d]=max(f[a][b][c][d],f[a][b-1][c][d]+k[now]);
                        if(c!=0) f[a][b][c][d]=max(f[a][b][c][d],f[a][b][c-1][d]+k[now]);
                        if(d!=0) f[a][b][c][d]=max(f[a][b][c][d],f[a][b][c][d-1]+k[now]);
                    }
                }
            }
        }
        cout<<f[card[1]][card[2]][card[3]][card[4]]<<endl;
        return 0;
    }
  • 相关阅读:
    c语言 判断文件是否存在
    lua 二进制函数使用
    linux sort 多列正排序,倒排序
    free命令学习 输出理解
    nginx 配置实现逻辑预算
    nginx 使用ctx实现数据共享,修改上下文
    lua中的数学库
    tornado文件上传实例
    ajax技术初识与应用
    web框架--XSS攻击和CSRF请求伪造
  • 原文地址:https://www.cnblogs.com/jiangyuechen/p/13055604.html
Copyright © 2011-2022 走看看