P6855「EZEC-4.5」走方格 TJ
前言
正解:动态规划
挺 duliu 一道题,难度较大 qwq。
PS:因为此篇题解前后改动较多,如果有什么错误请各位奆佬提出,本蒟蒻感激不尽 awa。
题意简述
给你一个 \(n\times m\) 大小的方格阵,可以把方格中的任意一个数改为 \(0\),每次从 \((1,1)\) 到 \((n,m)\) 的得分为路上所有数字的和。求每次改动数字后能得到的最大值的最小值。
法一:时间复杂度 \(Θ(m^2n^2)\) (TLE)
这但凡是个正常人都会想到吧……前两层循环枚举变为 \(0\) 的方格坐标,后两层按照正常的方格取数做法求最大值。
结果,被校 OJ 卡了没骗到分。
\(Code\)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int m,n,t,a[2005][2005];
ll ans=LONG_LONG_MAX,dp[2005][2005];
int main(){
scanf("%d %d",&m,&n);
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
scanf("%d",&a[i][j]);
}
}
for(int x=1;x<=m;x++){
for(int y=1;y<=n;y++){
memset(dp,0,sizeof(dp));
t=a[x][y];
a[x][y]=0;
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
dp[i][j]=max(dp[i][j-1],dp[i-1][j])+a[i][j];
}
}
ans=min(ans,dp[m][n]);
a[x][y]=t;
}
}
printf("%lld",ans);
return 0;
}
法二:正解,时间复杂度 \(Θ(mn)\)
PS * 2:因为 me 习惯用 \(m\) 表示行 \(n\) 表示列,所以下列题解就会这么写。
有点麻烦。
如果每个点只能遍历一次,那么必须不变值和变为 \(0\) 这两种情况需要同时考虑。
首先我们可以考虑先求出从 \((1,1)\) 点出发走到 \((i,j)\) 点和从 \((m,n)\)出发走到 \((i,j)\) 点能拿到的最大分数,分别存在 \(dp1\) 数组和 \(dp2\) 数组里。
这两个数组很好求,按照每个初学 DP 者都要打的取数板子就珂以了。至于为什么要求这两个数组,我先卖个关子,待会儿就知道了(逃。
我们知道,如果你从 \((1,1)\) 出发,在走的时候不经过某个坐标为 \((i,j)\) 的点(也就是绕过这个点),你有两种情况可以绕开它:
从左边绕。
从上边绕。
给这两种方法更严谨的定义 \((i>0)\) :
从左边绕:经过点 \((x,y-i)\)。
从上边绕:经过点 \((x-i,y)\)。
对于这两种情况,我们可以分别用两个二维数组 \(l\) (左边绕)和 \(d\) (上边绕)来存:
\(l_{i,j}\) 表示从左边绕过 \((i,j)\) 点能获得的最大值。
\(d_{i,j}\) 表示从上边绕过 \((i,j)\) 点能获得的最大值。
但是如何求这两个数组呢?
直接切入可能比较麻烦。这个时候我们可以先分析这种情况:

不管是往哪边绕,也不管前面怎么走,都紧贴着点 \((i,j)\) 过路方便分析,即,从左绕一定经过点 \((i,j-1)\),从上绕一定经过点 \((i-1,j)\)。
首先分析从左边绕的情况。

看图,蓝色区域表示从 \((1,1)\) 出发到点 \((i,j-1)\) 有可能会经过的区域,红色区域表示从点 \((i+1,j-1)\) 到 \((m,n)\) 有可能会经过的区域。至于为什么选这两个点呢,相信大家看图也能明白,因为选择这两个点可以做到经过的格子不重不漏,考虑到每种情况。
如果这么算,那么从点 \((i,j-1)\) 绕过去能拿到的最大分数就是:
\]
现在大家知道两个 \(dp\) 数组的意义了吧,就是用来求某个区域的最大分数的。因为如果每次循环到一个点就计算此点到终点的分数还需要两层循环会超时,基于走方格的方向是可逆的,我们只需要计算终点到每个点的最大分数就可以啦 OvO。
那我们现在只求了最贴近点 \((i,j)\) 的绕法,那我们如何求出往左绕的所有情况的最大值呢?
我们之前不是用了一个数组来存往左边绕的值吗?因为循环的顺序是从上到下,从左到右的,所以在求点 \((i,j)\) 的值时,我们已经把它左上方的所有值都求出来了。现在我们可以利用这些值,每一次,我们求当前 \(score\) 与之前最大分数的较大值,那每次都求最大值就是所有情况中的最大值。
那么最后的结果就是:
\]
至于为什么我们利用的是 \(l_{i,j-1}\),大家可以自己画图感知,这个格子就位于我们前面求的必须经过的那个格子 \((i,j-1)\),那么绕过它我们就会求必须经过点 \((i,j-2)\),这样我们就又需要考虑绕过这个格子的情况,就又必须经过点 \((i,j-3)\)……这么一层一层往左推,最后可以推到点 \((i,1)\),从而把每种情况都考虑到。
从上面绕分析方法也差不多,这里不多说画张图让读者感知一下。

(您看看这两张图多像,连大小都差不多26 KB)
最后求出 \(d_{i,j}\) 的式子为:
\]
最后求答案有些麻烦,因为题目要求的是变化后最能获得的最大分数的最小值,所以 \(\max\) 和 \(\min\) 是真的挺容易用混的,这里需要特别注意。
首先每对一个格子进行操作,最后得到的答案会是下列三种情况中的一种:
从左边绕过去得到的最大分数。
从上边绕过去得到的最大分数。
经过这个格子得到的最大分数。
前两个我们已经求解了,但其实第三种情况是灰常简单的!因为要保证经过点 \((i,j)\),所以我们只需要求 \(dp1_{i,j}+dp2{i,j}\) 就可以了。但是上面那个式子算了两次 \((i,j)\) 的值,而我们因为把它变成 \(0\) 了,就一次都不能算。所以还需要减去两个 \(a_{i,j}\)。
所以最后的答案终于可能被更新了 owo:
\]
最后再强调一遍要注意最大值和最小值别用反了啊! 别问我为什么知道(悲)。
\(Code\)
#include<bits/stdc++.h>
#define ll long long //记得要开long long哦!
using namespace std;
//温馨提示细节:因为最后答案还是求的最小值,所以 ans 需要定义极大值
ll m,n,ans=LONG_LONG_MAX,a[2005][2005],dp1[2005][2005],dp2[2005][2005],l[2005][2005],d[2005][2005];
int main(){
//输入
scanf("%lld %lld",&m,&n);
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
scanf("%lld",&a[i][j]);
}
}
//求两个 dp 数组的值
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
dp1[i][j]=max(dp1[i-1][j],dp1[i][j-1])+a[i][j];
}
}
for(int i=m;i;i--){
for(int j=n;j;j--){
dp2[i][j]=max(dp2[i+1][j],dp2[i][j+1])+a[i][j];
}
}
//核心代码开始
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
l[i][j]=max(l[i][j-1],dp1[i][j-1]+dp2[i+1][j-1]);
d[i][j]=max(d[i-1][j],dp1[i-1][j]+dp2[i-1][j+1]);
ans=min(ans,max(max(l[i][j],d[i][j]),dp1[i][j]+dp2[i][j]-2*a[i][j]));
}
}
//核心代码结束,输出答案
printf("%lld",ans);
return 0;
}
写在最后
这真的是一道很好的动态规划题,很考验思维,也有很多需要注意的细节。最后,看在本人写了那么久的份上,就请您随手点一下左下角那个小小的赞吧 qwq。
P6855「EZEC-4.5」走方格 TJ的更多相关文章
- LibreOJ #6007. 「网络流 24 题」方格取数 最小割 最大点权独立集 最大流
#6007. 「网络流 24 题」方格取数 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据 题目描述 ...
- Libre 6007 「网络流 24 题」方格取数 / Luogu 2774 方格取数问题 (网络流,最大流)
Libre 6007 「网络流 24 题」方格取数 / Luogu 2774 方格取数问题 (网络流,最大流) Description 在一个有 m*n 个方格的棋盘中,每个方格中有一个正整数.现要从 ...
- 洛谷比赛 「EZEC」 Round 4
洛谷比赛 「EZEC」 Round 4 T1 zrmpaul Loves Array 题目描述 小 Z 有一个下标从 \(1\) 开始并且长度为 \(n\) 的序列,初始时下标为 \(i\) 位置的数 ...
- macOS安装「oh my zsh」
目前常用的 Linux 系统和 OS X 系统的默认 Shell 都是 bash,但是真正强大的 Shell 是深藏不露的 zsh, 这货绝对是马车中的跑车,跑车中的飞行车,史称『终极 Shell』, ...
- Loj #2324. 「清华集训 2017」小 Y 和二叉树
Loj #2324. 「清华集训 2017」小 Y 和二叉树 小Y是一个心灵手巧的OIer,她有许多二叉树模型. 小Y的二叉树模型中,每个结点都具有一个编号,小Y把她最喜欢的一个二叉树模型挂在了墙上, ...
- Loj #2321. 「清华集训 2017」无限之环
Loj #2321. 「清华集训 2017」无限之环 曾经有一款流行的游戏,叫做 *Infinity Loop***,先来简单的介绍一下这个游戏: 游戏在一个 \(n \times m\) 的网格状棋 ...
- LOJ #6192. 「美团 CodeM 复赛」城市网络 (树上倍增)
#6192. 「美团 CodeM 复赛」城市网络 内存限制:64 MiB 时间限制:500 ms 标准输入输出 题目描述 有一个树状的城市网络(即 nnn 个城市由 n−1n-1n−1 条道路连接 ...
- Libre 6010「网络流 24 题」数字梯形 (网络流,最大费用最大流)
Libre 6010「网络流 24 题」数字梯形 (网络流,最大费用最大流) Description 给定一个由n 行数字组成的数字梯形如下图所示.梯形的第一行有m 个数字.从梯形的顶部的m 个数字开 ...
- Luogu 2764 最小路径覆盖问题 / Libre 6002 「网络流 24 题」最小路径覆盖 (网络流,最大流)
Luogu 2764 最小路径覆盖问题 / Libre 6002 「网络流 24 题」最小路径覆盖 (网络流,最大流) Description 给定有向图G=(V,E).设P是G的一个简单路(顶点不相 ...
随机推荐
- 浅析C++的函数式编程
前言 Java8在Java中通过lambda表达式.Stream API引入了函数式编程,那么C++中是否也支持函数式编程呢?答案是肯定的.目前关于C++进行函数式编程的语法探究的相关博客.文章并不多 ...
- Android开发万能Utils(工具大全)
AndroidUtils Android开发不得不收藏的Utils About AndroidUtilCode 是一个强大易用的安卓工具类库,它合理地封装了安卓开发中常用的函数,具有完善的 Demo ...
- 深入浅出,新一代跨平台抓包&调式利器Fiddler Everywhere
什么是Fiddler Everywhere? Fiddler Everywhere is a web debugging proxy for macOS, Windows, and Linux. Ca ...
- MySQL之where条件数据筛选
语法: -- select * from 表名 where 条件; 测试数据: -- 建表语句 create table `student` ( `sid` int(11) primary key a ...
- SuperEdge 云边隧道新特性:从云端SSH运维边缘节点
背景 在边缘集群的场景下边缘节点分布在不同的区域,且边缘节点和云端之间是单向网络,边缘节点可以访问云端节点,云端节点无法直接访问边缘节点,给边缘节点的运维带来很大不便,如果可以从云端SSH登录到边缘节 ...
- layui table 列宽百分比显示
var layer = layui.layer, form = layui.form, table = layui.table; var $ = layui.$; /*select gysmc,zyz ...
- Java运算中的类型转换
类型转换 运算中,不同类型的数据先转化为同一类型,然后进行运算 public class Dome04 { public static void main(String[] args) { //int ...
- SpringMVC(1)流程框架总体介绍
SpringMVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面.Spring 框架提供了构建 Web 应用程序的全功能MVC 模块,其功能和Strtus2 ...
- Nginx配置中的log_format用法梳理 (转)
nginx服务器日志相关指令主要有两条,一条是log_format,用来设置日志格式,另外一条是access_log,用来指定日志文件的存放路径.格式和缓存大小,一般在nginx的配置文件中日记配 ...
- JAVA WEB 用servlet实现分页,思路比较清晰和简单。
JAVA WEB 用servlet实现分页,思路比较清晰和简单.借鉴了其他大佬的思路.特别感谢. 是我第一次发表博客,如果有什么错误,欢迎大家指出!,谢谢 一.思路分析 前台一定是有类似这种的界面 点 ...