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

相关文章

一文详解SpringBoot中控制器的动态注册与卸载

《一文详解SpringBoot中控制器的动态注册与卸载》在项目开发中,通过动态注册和卸载控制器功能,可以根据业务场景和项目需要实现功能的动态增加、删除,提高系统的灵活性和可扩展性,下面我们就来看看Sp... 目录项目结构1. 创建 Spring Boot 启动类2. 创建一个测试控制器3. 创建动态控制器注

springboot如何通过http动态操作xxl-job任务

《springboot如何通过http动态操作xxl-job任务》:本文主要介绍springboot如何通过http动态操作xxl-job任务的问题,具有很好的参考价值,希望对大家有所帮助,如有错... 目录springboot通过http动态操作xxl-job任务一、maven依赖二、配置文件三、xxl-

HTML5 搜索框Search Box详解

《HTML5搜索框SearchBox详解》HTML5的搜索框是一个强大的工具,能够有效提升用户体验,通过结合自动补全功能和适当的样式,可以创建出既美观又实用的搜索界面,这篇文章给大家介绍HTML5... html5 搜索框(Search Box)详解搜索框是一个用于输入查询内容的控件,通常用于网站或应用程

Java调用C#动态库的三种方法详解

《Java调用C#动态库的三种方法详解》在这个多语言编程的时代,Java和C#就像两位才华横溢的舞者,各自在不同的舞台上展现着独特的魅力,然而,当它们携手合作时,又会碰撞出怎样绚丽的火花呢?今天,我们... 目录方法1:C++/CLI搭建桥梁——Java ↔ C# 的“翻译官”步骤1:创建C#类库(.NET

MyBatis编写嵌套子查询的动态SQL实践详解

《MyBatis编写嵌套子查询的动态SQL实践详解》在Java生态中,MyBatis作为一款优秀的ORM框架,广泛应用于数据库操作,本文将深入探讨如何在MyBatis中编写嵌套子查询的动态SQL,并结... 目录一、Myhttp://www.chinasem.cnBATis动态SQL的核心优势1. 灵活性与可

Mybatis嵌套子查询动态SQL编写实践

《Mybatis嵌套子查询动态SQL编写实践》:本文主要介绍Mybatis嵌套子查询动态SQL编写方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言一、实体类1、主类2、子类二、Mapper三、XML四、详解总结前言MyBATis的xml文件编写动态SQL

SpringBoot实现Kafka动态反序列化的完整代码

《SpringBoot实现Kafka动态反序列化的完整代码》在分布式系统中,Kafka作为高吞吐量的消息队列,常常需要处理来自不同主题(Topic)的异构数据,不同的业务场景可能要求对同一消费者组内的... 目录引言一、问题背景1.1 动态反序列化的需求1.2 常见问题二、动态反序列化的核心方案2.1 ht

golang实现动态路由的项目实践

《golang实现动态路由的项目实践》本文主要介绍了golang实现动态路由项目实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习... 目录一、动态路由1.结构体(数据库的定义)2.预加载preload3.添加关联的方法一、动态路由1

Python Selenium动态渲染页面和抓取的使用指南

《PythonSelenium动态渲染页面和抓取的使用指南》在Web数据采集领域,动态渲染页面已成为现代网站的主流形式,本文将从技术原理,环境配置,核心功能系统讲解Selenium在Python动态... 目录一、Selenium技术架构解析二、环境搭建与基础配置1. 组件安装2. 驱动配置3. 基础操作模

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

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