• #luogu整理 P1541 憨八龟 给爷爬(乌龟棋)


    luogu P1541 乌龟棋

    动态规划问题,讲一下状态设计的要领。

    状态设计

    f[a1][a2][a3][a4]表示1、2、3、4这四种牌分别用了a1 a2 a3 a4张之后能达到的最大路径。

    状态转移

    f[a1+1][a2][a3][a4] = max(f[a1+1][a2][a3][a4],f[a1][a2][a3][a4] + a[x+1]);
    f[a1][a2+1][a3][a4] = max(f[a1][a2+1][a3][a4],f[a1][a2][a3][a4] + a[x+2])
    f[a1][a2][a3+1][a4] = max(f[a1][a2][a3+1][a4],f[a1][a2][a3][a4] + a[x+3])
    f[a1][a2][a3][a4+1] = max(f[a1][a2][a3][a4+1],f[a1][a2][a3][a4] + a[x+4])
    

    初始化

    f[0][0][0][0] = a[1]也就是每张牌都没用,在起点的时候的分值达到了a[1]。

    状态设计过程

    首先看到两点:变量和范围。动态规划的第一步就是把所有可能影响结果的变量都单独放一维。然后再考虑是否能缩减、简化。

    这时候我们得到的方程是: f[i][a1][a2][a3][a4]表示走到i的时候,1、2、3、4分别用了a1、a2、a3、a4张牌,能够得到的最大值。那么我们的转移就是:

    f[i+1][a1+1][a2][a3][a4] = max(f[i+1][a1+1][a2][a3][a4],f[i][a1][a2][a3][a4] + a[i+1]);
    f[i+2][a1][a2+1][a3][a4] = max(f[i+2][a1][a2+1][a3][a4],f[i][a1][a2][a3][a4] + a[i+2]);
    f[i+3][a1][a2][a3+1][a4] = max(f[i+3][a1][a2][a3+1][a4],f[i][a1][a2][a3][a4] + a[i+3]);
    f[i+4][a1][a2][a3][a4+1] = max(f[i+4][a1][a2][a3][a4+1],f[i][a1][a2][a3][a4] + a[i+4]);
    

    根据题目给的范围我们可以很简单地知道复杂度:(O(MNprod_{i = 1}^{M}b_i)),空间直接整到了(350 imes 41^4 imes 4B= 989,016,350B = 943.1994915MB),很显然超出了内存限制,考虑缩减。

    联想到我们把01背包和无限背包降维打击成1维,利用的是他循环覆盖的特点,我们也可以把f的第一维去掉。这样复杂度就降下来了好多,时间也允许了。

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    int n,m;
    int a[400],k[5];
    int f[41][41][41][41];
    int main(){
        cin >> n >> m;
        for(int i = 1;i <= n; i++){
            cin >> a[i];
        }
        for(int i = 1;i <= m; i++){
            int t;
            cin >> t;
            k[t]++;
        }
        // for(int i = 1;i <= 4; i++) cout << k[i] << ' ';
        f[0][0][0][0] = a[1];
            for(int a1 = 0;a1 <= k[1]; a1++){
                for(int a2 = 0;a2 <= k[2]; a2++){
                    for(int a3 = 0;a3 <= k[3]; a3++){
                        for(int a4 = 0;a4 <= k[4]; a4++){
                            int x = a1 + a2 * 2 + a3 * 3 + a4 * 4 + 1;
                            if(a1+1 <= k[1]) f[a1+1][a2][a3][a4] = max(f[a1+1][a2][a3][a4],f[a1][a2][a3][a4] + a[x+1]);
                            if(a2+1 <= k[2]) f[a1][a2+1][a3][a4] = max(f[a1][a2+1][a3][a4],f[a1][a2][a3][a4] + a[x+2]);
                            if(a3+1 <= k[3]) f[a1][a2][a3+1][a4] = max(f[a1][a2][a3+1][a4],f[a1][a2][a3][a4] + a[x+3]);
                            if(a4+1 <= k[4]) f[a1][a2][a3][a4+1] = max(f[a1][a2][a3][a4+1],f[a1][a2][a3][a4] + a[x+4]);
                        }
                    }
                }
            }
        cout << f[k[1]][k[2]][k[3]][k[4]] << endl;
        return 0;
    }
    
  • 相关阅读:
    Finder 的分栏显示模式宽度调整
    IBAction作用相当于void,NSLog(@"被调用的方法名是%s",__func__);
    Trapping Rain Water
    Binary Tree Preorder Traversal
    Valid Parentheses
    Reverse Words in a String | LeetCode OJ | C++
    Gas Station|leetcode 贪心
    两个字符串“相等”
    Binary Tree Zigzag Level Order Traversal
    Add Binary
  • 原文地址:https://www.cnblogs.com/Cao-Yucong/p/12609678.html
Copyright © 2020-2023  润新知