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

相关文章

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小时制时间,详细内容请阅读本文,希望能对你有所帮助...

Python使用DeepSeek进行联网搜索功能详解

《Python使用DeepSeek进行联网搜索功能详解》Python作为一种非常流行的编程语言,结合DeepSeek这一高性能的深度学习工具包,可以方便地处理各种深度学习任务,本文将介绍一下如何使用P... 目录一、环境准备与依赖安装二、DeepSeek简介三、联网搜索与数据集准备四、实践示例:图像分类1.

Vue中动态权限到按钮的完整实现方案详解

《Vue中动态权限到按钮的完整实现方案详解》这篇文章主要为大家详细介绍了Vue如何在现有方案的基础上加入对路由的增、删、改、查权限控制,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、数据库设计扩展1.1 修改路由表(routes)1.2 修改角色与路由权限表(role_routes)二、后端接口设计

前端 CSS 动态设置样式::class、:style 等技巧(推荐)

《前端CSS动态设置样式::class、:style等技巧(推荐)》:本文主要介绍了Vue.js中动态绑定类名和内联样式的两种方法:对象语法和数组语法,通过对象语法,可以根据条件动态切换类名或样式;通过数组语法,可以同时绑定多个类名或样式,此外,还可以结合计算属性来生成复杂的类名或样式对象,详细内容请阅读本文,希望能对你有所帮助...

Nginx实现动态封禁IP的步骤指南

《Nginx实现动态封禁IP的步骤指南》在日常的生产环境中,网站可能会遭遇恶意请求、DDoS攻击或其他有害的访问行为,为了应对这些情况,动态封禁IP是一项十分重要的安全策略,本篇博客将介绍如何通过NG... 目录1、简述2、实现方式3、使用 fail2ban 动态封禁3.1 安装 fail2ban3.2 配

Vue3中的动态组件详解

《Vue3中的动态组件详解》本文介绍了Vue3中的动态组件,通过`component:is=动态组件名或组件对象/component`来实现根据条件动态渲染不同的组件,此外,还提到了使用`markRa... 目录vue3动态组件动态组件的基本使用第一种写法第二种写法性能优化解决方法总结Vue3动态组件动态