题意:有一块 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. jsp session/application

    session的增加读取 session.setAttribute("username", "张三"); String u = (String) session ...

  2. English trip -- VC(情景课)5 D

    Read 阅读 Listen and read. 听并读 Notice from Riverside Library Come and visit Riverside Library.The new ...

  3. Import Data from *.xlsx file to DB Table through OAF page(转)

    Use  Poi.jar Import Data from *.xlsx file to DB Table through OAF page Use Jxl.jar Import Data from ...

  4. 在EO中对数据的重复性进行验证

    只有在数据提交到EO中的时候才会执行set方法进行验证. 如果想要实现实时验证,可以在输入参数的地方添加事件,但是无需为此事件创建方法. 我的理解: 1.我们在页面上对内容进行修改的时候,OAF框架仅 ...

  5. The working copy needs to be upgraded svn: The working copy at

    错误信息: The working copy needs to be upgradedsvn: The working copy at 'F:\JAVA Project\PAW-VRVEIS-JJ-2 ...

  6. Vue---vue-cli 中的proxyTable解决开发环境中的跨域问题

    使用vue+vue-cli+axios+element-ui开发后台管理系统时,遇到一个问题,后台给了一个接口,我这边用axios请求数据,控制台总是报405错误和跨域错误 错误 405? 没见过!! ...

  7. poj 1163 The Triangle 搜索 难度:0

    The Triangle Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 37931   Accepted: 22779 De ...

  8. W1002 Symbol 'Create' is specific to a platform

    http://stackoverflow.com/questions/9099892/how-to-use-tformatsettings-create-without-being-specific- ...

  9. 日期控件:My97DatePicker

    My97DatePicker是一款非常灵活好用的日期控件.使用非常简单. 1.下载My97DatePicker组件包 下载地址:http://download.csdn.net/detail/emov ...

  10. Oracle 与Sql Server常用函数对比

    来自:http://topic.csdn.net/u/20080704/08/b2b8c42f-b0d6-4cda-98b1-6e4a279b4ff8.html 感谢楼主 函数 SQLServer和O ...