首页 > 其他分享 >「背包DP」科技庄园

「背包DP」科技庄园

时间:2023-03-17 17:11:13浏览次数:47  
标签:体力 10 庄园 int dp 背包 PFT DP

本题为3月17日23上半学期集训每日一题中A题的题解

题面

题目描述

Life种了一块田,里面种了有一些桃树。

Life对PFT说:“我给你一定的时间去摘桃,你必须在规定的时间之内回到我面前,否则你摘的桃都要归我吃!”

PFT思考了一会,最终答应了!

由于PFT的数学不好!它并不知道怎样才能在规定的时间获得最大的价值,

由于PFT不是机器人,所以他的体力并不是无限的,他不想摘很多的桃以至体力为0,而白白把桃给Life。同时PFT每次只能摘一棵桃树,,每棵桃树都可以摘K次(对于同一棵桃每次摘的桃数相同)。每次摘完后都要返回出发点(PFT一次拿不了很多)即Life的所在地(0,0)(试验田左上角的桃坐标是(1,1))。

PFT每秒只能移动一个单位,每移动一个单位耗费体力1(摘取不花费时间和体力,但只限上下左右移动)。

输入

第一行:四个数为N,M,TI,A 分别表示试验田的长和宽,Life给PFT的时间,和PFT的体力。

下面一个N行M列的矩阵桃田。表示每次每棵桃树上能摘的桃数。

接下来N行M列的矩阵,表示每棵桃最多可以采摘的次数K。

输出

一个数:PFT可以获得的最大的桃个数。

样例输入

4 4 13 20
10 0  0  0
0  0  10 0
0  0  10 0
0  0  0  0
1 0 0 0
0 0 2 0
0 0 4 0
0 0 0 0

样例输出

10

提示

样例说明:

可以摘到1次(1,1)和1次(2,3),体力和时间不满足再摘桃了。

范围:

对于30%的数据: $ 10 \leq M,N,TI,A \leq 50 $

对于100%的数据: $ 10 \leq M,N,TI,A \leq 100 $

此外对于100%的数据: $ 10 \leq k \leq 100 $

保证结果在long int范围内

思路分析

本题的题意就是让你在规定的时间限制和体力限制里摘更多的果子.如果我们把一棵树看成一个物品,把这棵树每次可以摘的果子看成它的价值,把这棵树可以摘的次数看成它的数量,把走到这棵树然后走回需要的时间(或体力,显然两者等值,注意要一来一回)看作商品占用的空间(由题意,此处需要的时间就是这个点到起点的曼哈顿距离),那么这就是一个经典的多重背包的模型.背包的容量就是两个限制的最小值(因为每走一步两个限制其实是一样的).此题数据量较小,直接使用朴素的多重背包即可完成.

不过这题有两个坑点一定要注意,第一是题目明确说明了:

他不想摘很多的桃以至体力为0

所以体力与时间不同,不能减小为0,所以体力实际上的限制量是要减一的.第二是这题是可能出现一颗果树不让摘的情况的,所以需要把第一个矩阵离线下来,在两个矩阵同一位置均不为0的时候,再处理成物品.

如果你还不会朴素多重背包,请先阅读背包九讲(如果打不开github也可以在集训队的群文件中搜索),或者这篇博客(可能需要一点魔法才能访问)进行学习,当然也可自行搜索博客等学习.在ACWing上有公开的朴素多重背包板子题,请尝试独立通过此题,然后再来做这道题.

参考代码

时间复杂度: \(O(min{TI,A}NMK)\)(K为总共可摘果子数)

空间复杂度: \(O(min{TI,A}NM)\)

#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3, "Ofast", "inline")
#include <bits/stdc++.h>

using namespace std;

using i64 = long long;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);

    int n, m, t, a;
    cin >> n >> m >> t >> a;
    int lit = min(t, a - 1); // 计算背包容量(注意体力不能为0,所以这里要减一)

    // 离线第一个矩阵,以便和第二个矩阵对比
    vector<vector<int>> gA(n + 1, vector<int>(m + 1));
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            cin >> gA[i][j];
        }
    }

    // 将输入的信息转换为背包问题中对应的信息
    int *cost = new int[n * m + 1]; // 物品占用空间
    int *val = new int[n * m + 1]; // 物品价值
    int *cnt = new int[n * m + 1]; // 物品数量
    int idx = 0; // 上述数组的统一下标,同时记录总数
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            int b;
            cin >> b;
            if (gA[i][j] && b) { // 当前位置有一颗能摘的果树
                cost[++idx] = i + j << 1; // 注意一来一回,所以要*2(<<1等价于*2,注意优先级)
                val[idx] = gA[i][j];
                cnt[idx] = b;
            }
        }
    }

    // 朴素多重背包模板(建议还是用空间压缩的,因为朴素的反而容易错)
    vector<vector<i64>> dp(idx + 1, vector<i64>(lit + 1, 0));
    for (int i = 1; i <= idx; i++) {
        for (int j = 1; j <= lit; j++) {
            for (int k = 0; k <= cnt[i]; k++) { // 别从1开始,需要先复制前一层
                if (j - k * cost[i] >= 0) {
                    dp[i][j] =
                        max(dp[i][j], dp[i - 1][j - k * cost[i]] + k * val[i]); // 别写成dp[i - 1][j],因为前面可能已经更新了当前的dp[i][j]
                } else {
                    break;
                }
            }
        }
    }

    cout << dp[idx][lit] << "\n";

    delete[] val;
    delete[] cost;
    return 0;
}

"正是我们每天反复做的事情,最终造就了我们,优秀不是一种行为,而是一种习惯" ---亚里士多德

标签:体力,10,庄园,int,dp,背包,PFT,DP
From: https://www.cnblogs.com/geministar/p/zstu23_3_17_A.html

相关文章

  • UDP聊天实现
    1publicclassA{2publicstaticvoidmain(String[]args)throwsIOException{3DatagramSocketsocket=newDatagramSocket(8888);4......
  • 37、linux安装、卸载软件命令dpkg
    dpkg是DebianPackager的简写。为Debian专门开发的套件管理系统,方便软件的安装、更新及移除。所有源自Debian的Linux发行版都使用dpkg,例如Ubuntu、Knoppix......
  • DP Drone App使用支持
    DPDroneApp使用支持DPDrone isaUAV toyremotecontrolapp.DPDrone 是一款无人机玩具遥控App。ThemobilephonesendsthecontroldatatothetoyUAV th......
  • 一类特殊的区间 dp
    这类题目大概都是每次可以消除一个区间,并加上一些分数,然后合并左右。这类题目的特点是区间外也会对区间的dp值产生影响,因此不能采用普通的区间dp。CF1107EVasyaand......
  • wordpress博客系统用户密码穷举
    这里使用的是kali环境中自带的wpscan,这是一款漏洞扫描工具,当然也可以用来穷举爆破。https://wpscan.com/profile首先注册账号,获取APIwpscan--urlhttp://www.redteam.c......
  • in check_call raise CalledProcessError(retcode, cmd)——subprocess.CalledProcess
    BuildingHabitat-Sim时候的erro运行命令:./build.sh--headless--bulletincheck_callraiseCalledProcessError(retcode,cmd)subprocess.CalledProcessError:Com......
  • 基于大衍数构造的无六环稀疏校验矩阵LDPC误码率matlab仿真,附带检测H中是否存在六环,八
    1.算法描述      近年来,ldpc码的优越性得到国内外科研工作者关注,并且已成为现代通信系统不可或缺的部分,被用来检测和修正由信道效应如噪声、衰减和干扰等引起的信息......
  • 「背包DP」合唱队形
    本题为3月16日23上半学期集训每日一题中A题的题解题面题目描述金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间他自己专用的很宽敞的房间。更让他高兴的是,妈妈......
  • 【P2109 [NOI2007]】 生成树计数(状压 dp + 矩阵快速幂)
    状压dp+矩阵快速幂优化。感觉题解区几篇题解说得云里雾里的……也没有一定的证明……Link.SolutionPart1dp状态设计发现\(k\)的范围很小,具有很强的指向性——......
  • 线性dp
    C-TakandCards(atcoder.jp)  解:设dp[i][j][k]表示为:正在处理第i张牌,从一共i张牌中选j张,组成的数为k初始状态:dp[0][0][0]=1ifx+k<=A*n,dp[i+1][j+1][x+k......