HDU-2571 命运 广度优先搜索BFS+动态规划DP 题解

2023-10-24 05:11

本文主要是介绍HDU-2571 命运 广度优先搜索BFS+动态规划DP 题解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

● 本题解会有详细的分析,适合初学者阅读
## 原题

Problem Description

穿过幽谷意味着离大魔王lemon已经无限接近了!
可谁能想到,yifenfei在斩杀了一些虾兵蟹将后,却再次面临命运大迷宫的考验,这是魔王lemon设下的又一个机关。要知道,不论何人,若在迷宫中被困1小时以上,则必死无疑!
可怜的yifenfei为了去救MM,义无返顾地跳进了迷宫。让我们一起帮帮执着的他吧!
命运大迷宫可以看成是一个两维的方格阵列,如下图所示:

yifenfei一开始在左上角,目的当然是到达右下角的大魔王所在地。迷宫的每一个格子都受到幸运女神眷恋或者痛苦魔王的诅咒,所以每个格子都对应一个值,走到那里便自动得到了对应的值。
现在规定yifenfei只能向右或者向下走,向下一次只能走一格。但是如果向右走,则每次可以走一格或者走到该行的列数是当前所在列数倍数的格子,即:如果当前格子是(x,y),下一步可以是(x+1,y),(x,y+1)或者(x,y*k) 其中k>1。
为了能够最大把握的消灭魔王lemon,yifenfei希望能够在这个命运大迷宫中得到最大的幸运值。

Input

输入数据首先是一个整数C,表示测试数据的组数。
每组测试数据的第一行是两个整数n,m,分别表示行数和列数(1<=n<=20,10<=m<=1000);
接着是n行数据,每行包含m个整数,表示n行m列的格子对应的幸运值K ( |k|<100 )。

Output

请对应每组测试数据输出一个整数,表示yifenfei可以得到的最大幸运值。

Sample Input

1
3 8
9 10 10 10 10 -10 10 10
10 -11 -1 0 2 11 10 -20
-11 -11 10 11 2 10 -10 -10

Sample Output

52

题目分析

请耐心看到底~本题就一道DP水题,不要被吓住

那张**图太瘆人了,会影响你做题的,就不放上来了~

首先,如果你认为这道题是搜索,那么也无伤大雅,因为他还真是搜索

但不是DFS,因为也是在图中根据代价找路径,但是:这不是迷宫,你可以选择任何一条对答案有正贡献的路径,那么深搜绝对不是这道题的优选解决方案

那考虑一下BFS吧,我们从左上角出发,根据题目描述,我们一共有三种移动方式,我们走到一个点时,先将三种走法全部入队,同时用一个二维图记录每个坐标点的幸运值,在维护队列时,以后的坐标只有在大于先前坐标点的幸运值的时候,才允许该点入队,我们实现一下

#include <bits/stdc++.h>
using namespace std;
const int N = 30, M = 1100;
int g[N][M], max1, ans, n, m, val[N][M];typedef struct node{int x, y, w;}node;
queue<node> q;void bfs(){struct node head, tail, now;int x, y, i, j, d;head.x = head.y = 1;head.w = g[1][1];q.push(head);while (!q.empty()){head = q.front();q.pop();if (head.x == n && head.y == m){if (head.w > max1) max1 = head.w;}now.x = head.x + 1;now.y = head.y;now.w = head.w + g[now.x][now.y];if (now.x >= 1 && now.y >= 1 && now.x <= n && now.y <= m && val[now.x][now.y] < now.w){val[now.x][now.y] = now.w;q.push(now);}now.x = head.x;now.y = head.y + 1;now.w = head.w + g[now.x][now.y];if (now.x >= 1 && now.y >= 1 && now.x <= n && now.y <= m && val[now.x][now.y] < now.w){val[now.x][now.y] = now.w;q.push(now);}now.x = head.x;for (d = 2; d <= m; d++){now.y = head.y * d;if (now.y > m) break;now.w = head.w + g[now.x][now.y];if (now.x >= 1 && now.y >= 1 && now.x <= n && now.y <= m && val[now.x][now.y] < now.w){val[now.x][now.y] = now.w;q.push(now);}}}return;
}int main(){int t, i, j; cin >> t;while (t--){cin >> n >> m;memset(val, 0, sizeof(val));for (i = 1; i <= n; i++)for (j = 1; j <= m; j++) cin >> g[i][j];max1 = INT_MIN;bfs();cout << max1 << endl;}return 0;
}

???WTF,,,这么长,这么麻烦???思路可能不大对…我们还是再分析分析题吧~

这个玄学的人要取得最大的幸运值,还要从左上角走到右下角,我们读入幸运值的时候,可能会感觉到一丝熟悉感:这,莫非是DP?

这次猜对了。下面分析一下DP的思路:一共有三种走法:横着走、竖着走、跳着走。那么我们用 d p [ i ] [ j ] dp[i][j] dp[i][j]表示坐标为走到 ( i , j ) (i,j) (i,j)处的最大幸运值,那么我们可以推导出状态转移方程:

  • 横着走: d p [ i ] [ j + 1 ] = m a x ( d p [ i ] [ j + 1 ] , d p [ i ] [ j ] + g [ i ] [ j + 1 ] ) dp[i][j + 1] = max(dp[i][j + 1], dp[i][j] + g[i][j + 1]) dp[i][j+1]=max(dp[i][j+1],dp[i][j]+g[i][j+1])
  • 竖着走: d p [ i + 1 ] [ j ] = m a x ( d p [ i + 1 ] [ j ] , d p [ i ] [ j ] + g [ i + 1 ] [ j ] ) dp[i + 1][j] = max(dp[i + 1][j ], dp[i][j] + g[i +1][j]) dp[i+1][j]=max(dp[i+1][j],dp[i][j]+g[i+1][j])
  • 跳着走: d p [ i ] [ j ∗ k ] = m a x ( d p [ i ] [ j ∗ k ] , d p [ i ] [ j ] + g [ i ] [ j ∗ k ] ) dp[i][j * k] = max(dp[i][j * k], dp[i][j] + g[i][j * k]) dp[i][jk]=max(dp[i][jk],dp[i][j]+g[i][jk])

以横着走为例,我们来分析一下状态转移方程是如何推导出来的:

不妨设当前位置的坐标 ( i , j + 1 ) (i, j + 1) (i,j+1),假设我们通过上述三种方式都能够到达这个点:

无论是那种方式,如果是第一次到达,那么幸运值应该立即被记录下来,由于数组初始化为0了,取一下MAX自然就更新了

如果是第n次到达,由于我们是乱序访问的,因此访问到再次访问这个点的时候,需要将本次访问带来的新值与历史的记录值进行比较,留下较大的值,这便是 m a x ( d p [ i ] [ j + 1 ] , d p [ i ] [ j ] + g [ i ] [ j + 1 ] ) max(dp[i][j + 1], dp[i][j] + g[i][j + 1]) max(dp[i][j+1],dp[i][j]+g[i][j+1])的含义

一道水题分析这么多,,,不大合适。上DP代码吧

#include <bits/stdc++.h>
using namespace std;
int g[30][10010];
int dp[30][10010];int main(){int c = 0; cin >> c;while(c--){int n, m; cin >> n >> m;memset(g, 0, sizeof(g));for(int i = 1; i <= n; i++){for(int j = 1; j <= m; j++){cin >> g[i][j];dp[i][j] = INT_MIN;} }dp[1][1] = g[1][1];for(int i = 1; i <= n; i++){for(int j = 1; j <= m; j++){if(i + 1 <= n) dp[i + 1][j] = max(dp[i + 1][j], dp[i][j] + g[i + 1][j]);if(j + 1 <= m) dp[i][j + 1] = max(dp[i][j + 1], dp[i][j] + g[i][j + 1]);for(int k = 2; k <= m / j; k++) dp[i][j * k] = max(dp[i][j * k], dp[i][j] + g[i][j * k]);}}cout << dp[n][m] << endl;}return 0;
}

2; k <= m / j; k++) dp[i][j * k] = max(dp[i][j * k], dp[i][j] + g[i][j * k]);
}
}
cout << dp[n][m] << endl;
}
return 0;
}


这篇关于HDU-2571 命运 广度优先搜索BFS+动态规划DP 题解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/272923

相关文章

慢sql提前分析预警和动态sql替换-Mybatis-SQL

《慢sql提前分析预警和动态sql替换-Mybatis-SQL》为防止慢SQL问题而开发的MyBatis组件,该组件能够在开发、测试阶段自动分析SQL语句,并在出现慢SQL问题时通过Ducc配置实现动... 目录背景解决思路开源方案调研设计方案详细设计使用方法1、引入依赖jar包2、配置组件XML3、核心配

springboot使用Scheduling实现动态增删启停定时任务教程

《springboot使用Scheduling实现动态增删启停定时任务教程》:本文主要介绍springboot使用Scheduling实现动态增删启停定时任务教程,具有很好的参考价值,希望对大家有... 目录1、配置定时任务需要的线程池2、创建ScheduledFuture的包装类3、注册定时任务,增加、删

SpringBoot基于配置实现短信服务策略的动态切换

《SpringBoot基于配置实现短信服务策略的动态切换》这篇文章主要为大家详细介绍了SpringBoot在接入多个短信服务商(如阿里云、腾讯云、华为云)后,如何根据配置或环境切换使用不同的服务商,需... 目录目标功能示例配置(application.yml)配置类绑定短信发送策略接口示例:阿里云 & 腾

MySQL中动态生成SQL语句去掉所有字段的空格的操作方法

《MySQL中动态生成SQL语句去掉所有字段的空格的操作方法》在数据库管理过程中,我们常常会遇到需要对表中字段进行清洗和整理的情况,本文将详细介绍如何在MySQL中动态生成SQL语句来去掉所有字段的空... 目录在mysql中动态生成SQL语句去掉所有字段的空格准备工作原理分析动态生成SQL语句在MySQL

Java调用C++动态库超详细步骤讲解(附源码)

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代... 目录一、直接调用C++库第一步:动态库生成(vs2017+qt5.12.10)第二步:Java调用C++

C#如何动态创建Label,及动态label事件

《C#如何动态创建Label,及动态label事件》:本文主要介绍C#如何动态创建Label,及动态label事件,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C#如何动态创建Label,及动态label事件第一点:switch中的生成我们的label事件接着,

SpringCloud动态配置注解@RefreshScope与@Component的深度解析

《SpringCloud动态配置注解@RefreshScope与@Component的深度解析》在现代微服务架构中,动态配置管理是一个关键需求,本文将为大家介绍SpringCloud中相关的注解@Re... 目录引言1. @RefreshScope 的作用与原理1.1 什么是 @RefreshScope1.

MyBatis 动态 SQL 优化之标签的实战与技巧(常见用法)

《MyBatis动态SQL优化之标签的实战与技巧(常见用法)》本文通过详细的示例和实际应用场景,介绍了如何有效利用这些标签来优化MyBatis配置,提升开发效率,确保SQL的高效执行和安全性,感... 目录动态SQL详解一、动态SQL的核心概念1.1 什么是动态SQL?1.2 动态SQL的优点1.3 动态S

mybatis-plus 实现查询表名动态修改的示例代码

《mybatis-plus实现查询表名动态修改的示例代码》通过MyBatis-Plus实现表名的动态替换,根据配置或入参选择不同的表,本文主要介绍了mybatis-plus实现查询表名动态修改的示... 目录实现数据库初始化依赖包配置读取类设置 myBATis-plus 插件测试通过 mybatis-plu

基于Canvas的Html5多时区动态时钟实战代码

《基于Canvas的Html5多时区动态时钟实战代码》:本文主要介绍了如何使用Canvas在HTML5上实现一个多时区动态时钟的web展示,通过Canvas的API,可以绘制出6个不同城市的时钟,并且这些时钟可以动态转动,每个时钟上都会标注出对应的24小时制时间,详细内容请阅读本文,希望能对你有所帮助...