题意:有一块 n * n 大小的方形区域,要从左上角 (1,1)走到右下角(n,n),每个格子都有通过所需的时间,并且每次所走的下一格到终点的最短时间必须比当前格子走到重点的最短时间短,问一共有多少种走法。

这道题还是很明显的 DP 的,而且鉴于走到相邻格点可以上下左右走,所以我很快就锁定了记忆化搜索这种 DP 方式,但是事实上我的思路大方向的确没有错误,但是我仍然没有很好地挖掘题目的信息。我的想法是,某点到结尾的最短距离我可以转化成到起始点的最短距离,这样我就能从开头的点开始遍历,并且在遍历的时候,如果前后左右有点可以被当前的点优化(即从当前点走到下个点所花总时间比下个点上原本的最短时间还要短,那么我就用当前点优化下一个点,并继续从下一个点 DFS ),我觉得我想的挺对的,而且事实上我认为我的做法本身是可以解这题的,但是仍然会超时。

恩,其实到这里,问题都很明显了,记忆化搜索原本就是很有效地解决超时的一种手段,我之所以超时是因为我用的根本就不是记忆化搜索,而是很普通的 DPS ,DP 数组也只是为了便于传递状态而不是用于记忆,归根结底是我对记忆化搜索的认识还不够,我并没有掌握它,更没有理解记忆究竟是怎么样的,这之前写的两道记忆化搜索的题目其实都有一个共同点,用 DP 数组记录最优解,当再次遍历到这个点的时候就能够直接输出这个 DP 值,而在图中上下左右走根本只是一个题目的出现方式而已。

对题目的理解不到位也是很严重的一个问题,在本题中,已经很清楚地说明了下一个格子到终点的最短时间要比这一个格子到终点的最短时间短,很明显,我只要现处理出每一个点到终点的最短时间,这道题就和之前做的 hdu 1078 几乎一样了。

预处理出最短路径的方法我用的是 BFS ,从终点开始,每当周围有某个点可以用当前点优化,就将它优化后放回队列继续执行操作,当处理出最短路径之后,再用记忆化搜索的方式对整个图 DFS 一遍,用 DP 数组记录每个点到终点共有多少条路可以走,这样就可以得到答案了。

首先是我 TLE 的纯 DFS 代码:

 #include<stdio.h>
#include<string.h>
#define ll long long int n;
ll dp[][],m[][],t[][];
int xx[]={,-,,};
int yy[]={,,,-}; void dfs(int x,int y){
int i,j;
for(i=;i<;i++){
int dx=x+xx[i],dy=y+yy[i];
if(dx>=&&dx<=n&&dy>=&&dy<=n){
if(dp[dx][dy]==-||(dp[dx][dy]>dp[x][y]+t[dx][dy])){
dp[dx][dy]=dp[x][y]+t[dx][dy];
m[dx][dy]=m[x][y];
dfs(dx,dy);
}
else if(dp[dx][dy]==dp[x][y]+t[dx][dy]){
m[dx][dy]=;
for(j=;j<;j++){
int ddx=dx+xx[j],ddy=dy+yy[j];
if(ddx>=&&ddx<=n&&ddy>=&&ddy<=n&&(dp[ddx][ddy]+t[dx][dy]==dp[dx][dy])){
m[dx][dy]+=m[ddx][ddy];
}
} dfs(dx,dy);
}
}
}
} int main(){
while(scanf("%d",&n)!=EOF){
int i,j;
memset(dp,-,sizeof(dp));
memset(m,,sizeof(m));
for(i=;i<=n;i++){
for(j=;j<=n;j++){
scanf("%I64d",&t[i][j]);
}
}
dp[][]=t[][];
m[][]=;
dfs(,);/*
printf("dp:\n");
for(i=1;i<=n;i++){
for(j=1;j<=n;j++){
printf("%d ",dp[i][j]);
}
printf("\n");
}
printf("m:\n");
for(i=1;i<=n;i++){
for(j=1;j<=n;j++){
printf("%d ",m[i][j]);
}
printf("\n");
}*/
printf("%I64d\n",m[n][n]);
}
return ;
}

然后是我用 BFS 处理最短路径再记忆化搜索的代码:

 #include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
#define ll long long int n,c; struct point{
int x,y;
}; ll m[][],dp[][];
int t[][];
int xx[]={,-,,};
int yy[]={,,,-};
bool in[][]; void bfs(){
int i;
point p,p1;
p1.x=n;
p1.y=n;
in[p1.x][p1.y]=;
queue<point>q;
q.push(p1);
m[n][n]=t[n][n];
while(!q.empty()){
p=q.front();
q.pop();
in[p.x][p.y]=;
for(i=;i<;i++){
p1.x=p.x+xx[i];
p1.y=p.y+yy[i];
if(p1.x>=&&p1.x<=n&&p1.y>=&&p1.y<=n&&(m[p1.x][p1.y]==-||m[p1.x][p1.y]>m[p.x][p.y]+t[p1.x][p1.y])){
m[p1.x][p1.y]=m[p.x][p.y]+t[p1.x][p1.y];
if(!in[p1.x][p1.y]){
q.push(p1);
in[p1.x][p1.y]=;
}
}
}
}
} long long dfs(int x,int y){
if(x==n&&y==n)return ;
if(dp[x][y])return dp[x][y];
int i;
for(i=;i<;i++){
int dx=x+xx[i],dy=y+yy[i];
if(dx>=&&dx<=n&&dy>=&&dy<=n&&m[dx][dy]<m[x][y]){
dp[x][y]+=dfs(dx,dy);
}
}
return dp[x][y];
} int main(){
while(scanf("%d",&n)!=EOF){
int i,j;
memset(m,-,sizeof(m));
memset(dp,,sizeof(dp));
memset(in,,sizeof(in));
for(i=;i<=n;i++){
for(j=;j<=n;j++){
scanf("%d",&t[i][j]);
}
}
bfs();
printf("%I64d\n",dfs(,));
}
return ;
}

hdu1428 记忆化搜索(BFS预处理最短路径和+DP+DFS)的更多相关文章

  1. hdu1428(记忆化搜索)

    题意:“他考虑从A区域到B区域仅当存在一条从B到机房的路线比任何一条从A到机房的路线更近(否则可能永远都到不了机房了…”这句话一定要理解清楚.就是说,对于当前位置,如果下一个状态与终点的最短距离大于或 ...

  2. luogu1514 [NOIp2010]引水入城 (bfs+记忆化搜索)

    我们先bfs一下看看是否能到最底下的所有点 如果不能的话,直接把不能到的那几个数一数就行了 如果能的话: 可以发现(并不可以)某格能到达的最底下的格子一定是一个连续的区间 (因为如果不连续的话,我们先 ...

  3. 【bzoj1415】[Noi2005]聪聪和可可 期望记忆化搜索

    题目描述 输入 数据的第1行为两个整数N和E,以空格分隔,分别表示森林中的景点数和连接相邻景点的路的条数. 第2行包含两个整数C和M,以空格分隔,分别表示初始时聪聪和可可所在的景点的编号. 接下来E行 ...

  4. 专题1:记忆化搜索/DAG问题/基础动态规划

      A OpenJ_Bailian 1088 滑雪     B OpenJ_Bailian 1579 Function Run Fun     C HDU 1078 FatMouse and Chee ...

  5. 二进制数(dp,记忆化搜索)

    二进制数(dp,记忆化搜索) 给定k个<=1e6的正整数x(k不大于10),问最小的,能被x整除且只由01组成的数. 首先,dp很好写.用\(f[i][j]\)表示i位01串,模ki的值是j的数 ...

  6. hdu1978How many ways (记忆化搜索+DFS)

    Problem Description 这是一个简单的生存游戏,你控制一个机器人从一个棋盘的起始点(1,1)走到棋盘的终点(n,m).游戏的规则描述如下: 1.机器人一开始在棋盘的起始点并有起始点所标 ...

  7. UVA 103 Stacking Boxes (dp + DAG上的最长路径 + 记忆化搜索)

     Stacking Boxes  Background Some concepts in Mathematics and Computer Science are simple in one or t ...

  8. uva 10581 - Partitioning for fun and profit(记忆化搜索+数论)

    题目链接:uva 10581 - Partitioning for fun and profit 题目大意:给定m,n,k,将m分解成n份,然后依照每份的个数排定字典序,而且划分时要求ai−1≤ai, ...

  9. hdoj1078(介绍记忆化搜索及其模板)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1078 思路: 这是一道典型的记忆化搜索模板题. 先介绍记忆化搜索,本质是搜索+DP. 一般说来,动态规 ...

随机推荐

  1. Unity动态创建FBX模型配置文件的存放路径

    创建前目录结构: 创建后的目录结构: using System.Collections; using System.Collections.Generic; using UnityEngine; us ...

  2. 将数组划分成连续子序列 Split Array into Consecutive Subsequences

    2018-08-04 20:47:43 问题描述: 问题描述: 本题需要的是将一个数组划分成子序列,保证每个子序列是连续的,并且长度要大于等于3. 解题思路是使用贪心算法,首先对数组中的数字进行计数, ...

  3. 20 多继承 MRO 算法 深度优先遍历 super

    类的多继承 一个类可以继承多个无关的类. 一个类可以被多个无关的类继承 1.经典类. 在python2.2之前. 已经是历史了. MRO 采用的是树形结构的深度递归遍历(一条道跑到黑) 2.新式类 在 ...

  4. 『PyTorch』第九弹_前馈网络简化写法

    『PyTorch』第四弹_通过LeNet初识pytorch神经网络_上 『PyTorch』第四弹_通过LeNet初识pytorch神经网络_下 在前面的例子中,基本上都是将每一层的输出直接作为下一层的 ...

  5. HDU-3480 Division (四边形不等式优化DP)

    题目大意:将n个数分成m组,将每组的最大值与最小值的平方差加起来,求最小和. 题目分析:先对数排序.定义状态dp(i,j)表示前 j 个数分成 i 组得到的最小和,则状态转移方程为dp(i,j)=mi ...

  6. 使用opatch工具 打补丁Patch 21352635 -(Database Patch Set Update 11.2.0.4.8)

    Patch 21352635 - Database Patch Set Update 11.2.0.4.8 一.OPatch工具检查及升级 OPatch工具包,在安装目录$ORACLE_HOME下,P ...

  7. iOS UI-UIScrollView控件实现图片缩放功能

    一.缩放 1.简单说明: 有些时候,我们可能要对某些内容进行手势缩放,如下图所示 UIScrollView不仅能滚动显示大量内容,还能对其内容进行缩放处理.也就是说,要完成缩放功能的话,只需要将需要缩 ...

  8. List原理

    ArrayList: ArrayList是一个可变数组实现,实现了List接口的所有方法,并允许存取null值.ArrayList基本上等同与Vector,但它只对writeObject()和read ...

  9. spring AOP自定义注解 实现日志管理

    今天继续实现AOP,到这里我个人认为是最灵活,可扩展的方式了,就拿日志管理来说,用Spring AOP 自定义注解形式实现日志管理.废话不多说,直接开始!!! 关于配置我还是的再说一遍. 在appli ...

  10. jsoupa-解析遍历一个HTML

    解析个遍历一个HTML文档 String html ="<html><head><title>First parse</title></ ...