就我的理解来说这个题,本质上是一个DP题,不应该说是搜索,因为我的做法是把表格中所有的数据都找到,使用队列暴力来遍历出所有状态,因为题目中的数据范围小,所有耗时也小。

  首先分析箱子是一个被动物体,人是主动物体,箱子的移动取决于人的移动,所以在bfs中只需要让人去移动,进而带动箱子就可以了。我们使用dp[x1][y1][x2][y2]来记录状态,分别代表人和箱子的位置。在队列实现DP的过程中,我们必须要把当前所在的情况标记为未走过,这个很重要。有人可能会质疑,这样可能导致无限的入队列,导致死循环,所以需要一个技巧,首先新的状态是否更新跟这个状态是否被标记无关,所以能否让这个点入队列,需要首先满足状态值得更新的条件,所以我们不可能去走无意义的回头路,不可能会产生走过来走过去,从而导致死循环的情况。然后就要满足这个点未被标记的情况,才能入队列,标记这个点。

  当然有人也会问,只要把状态更新了就可以了,干嘛非要入队列呢?如果不仅队列,更新的仅仅是这个状态,其他的状态无法经过他转移,无法获得最优子结构,就不符合DP的思想,就是错误的了。(当然这个地方可能也仅仅是我不懂,但是这个标记方法还是很重要的),我给出一个例子吧。

0 0 0 0 0 0

0 0 1 1 1 0

0 0 1 4 0 0

0 0 1 2 1 0

0 0 0 0 3 0

0 0 0 0 1 0

0 0 0 0 0 0

我相信你很快就能找出两种方法来,往上走耗费的步数多,在bfs过程中也是后来达到的点,所以bfs第一次到两个加粗的0的时候,耗费步数少,但是推的次数多,而题目中要求最小的推数,与走的步数无关,所以这点必须更新并且入队列更新其他的点,如果我们没有把以前的标记消除,导致入队列失败,更新失败,答案出错。

最后一句话总结,在队列实现dp的过程中,一定记着把以前的标记消除,让新的点入队列,更新其他的状态,才能得到最后的最优解。

代码如下:

#include<iostream>
#include<cstdio>
#include<queue>
#include<cmath>
#include<cstring>
using namespace std;
#define maxn 10
#define INF 999999999
int dp[maxn][maxn][maxn][maxn],n,m,maps[maxn][maxn];
int go[][] = {{,},{-,},{,},{,-}};
int vis[maxn][maxn][maxn][maxn],endx,endy;
struct Node
{
int x1,y1,x2,y2;
Node () {};
Node(int xx1,int yy1,int xx2,int yy2)
{
x1 = xx1;
y1 = yy1;
x2 = xx2;
y2 = yy2;
}
};
void mark(Node a)
{
vis[a.x1][a.y1][a.x2][a.y2] = ;
}
bool ok(int x,int y)
{
return (x>=&&x<n && y>=&&y<m && maps[x][y]!=);
}
int bfs(Node start)
{
queue<Node> que;
memset(vis,,sizeof(vis));
while(!que.empty()) que.pop();
que.push(start);
dp[start.x1][start.y1][start.x2][start.y2] = ;
//mark(start);
while(!que.empty())
{
Node now = que.front();
que.pop();
int x1 = now.x1,y1 = now.y1;
int x2 = now.x2,y2 = now.y2;
vis[x1][y1][x2][y2] = ;///进入队列,消除标记
int xx1,xx2,yy1,yy2;
for(int i = ; i < ; i++)
{
xx1 = x1 + go[i][];
yy1 = y1 + go[i][];
if(ok(xx1,yy1))
{
if(xx1 == x2 && yy1 == y2)
{
xx2 = x2 + go[i][];
yy2 = y2 + go[i][];
if(ok(xx2,yy2))
{
if(dp[xx1][yy1][xx2][yy2]==- || dp[xx1][yy1][xx2][yy2]>dp[x1][y1][x2][y2]+)///第一层检验
{
dp[xx1][yy1][xx2][yy2] = dp[x1][y1][x2][y2]+;///更新当前点状态
if(!vis[xx1][yy1][xx2][yy2])
{
Node nxt(xx1,yy1,xx2,yy2);
mark(nxt);///进入队列,更新其他点
que.push(nxt);
}
} }
}
else
{
if(dp[xx1][yy1][x2][y2]== - || dp[xx1][yy1][x2][y2]>dp[x1][y1][x2][y2])
{
dp[xx1][yy1][x2][y2] = dp[x1][y1][x2][y2];
if(!vis[xx1][yy1][x2][y2])
{
Node nxt(xx1,yy1,x2,y2);
mark(nxt);
que.push(nxt);
}
}
}
}
}
}
int ans = INF;
for(int i = ; i < n; i++)
{
for(int j = ; j < m; j++)
{
//printf("dp[%d][%d] = %d\n",i,j,dp[i][j][endx][endy]);
if(dp[i][j][endx][endy] != -)
ans = min(ans,dp[i][j][endx][endy]);
}
}
if(ans != INF) return ans;
return -;
}
int main()
{
while(~scanf("%d%d",&m,&n))
{
if(n+m == ) break;
Node start;
for(int i = ; i < n; i++)
{
for(int j = ; j < m; j++)
{
scanf("%d",&maps[i][j]);
if(maps[i][j] == )
{
start.x2 = i;
start.y2 = j;
}
if(maps[i][j] == )
{
start.x1 = i;
start.y1 = j;
}
if(maps[i][j] == )
{
endx = i;
endy = j;
}
}
}
memset(dp,-,sizeof(dp));
int ans = bfs(start);
printf("%d\n",ans);
}
return ;
}

UVALive 2147 Push!!(队列实现DP)的更多相关文章

  1. hdu3401:单调队列优化dp

    第一个单调队列优化dp 写了半天,最后初始化搞错了还一直wa.. 题目大意: 炒股,总共 t 天,每天可以买入na[i]股,卖出nb[i]股,价钱分别为pa[i]和pb[i],最大同时拥有p股 且一次 ...

  2. SCOI 股票交易 单调队列优化dp

    这道题 我很蒙.....首先依照搞单调队列优化dp的一般思路 先写出状态转移方程 在想法子去优化 这个题目中说道w就是这一天要是进行操作就是从前w-1天转移而来因为之前的w天不允许有操作!就是与这些天 ...

  3. 「学习笔记」单调队列优化dp

    目录 算法 例题 最大子段和 题意 思路 代码 修剪草坪 题意 思路 代码 瑰丽华尔兹 题意 思路 代码 股票交易 题意 思路 代码 算法 使用单调队列优化dp 废话 对与一些dp的转移方程,我们可以 ...

  4. 【转】单调队列优化DP

    转自 : http://www.cnblogs.com/ka200812/archive/2012/07/11/2585950.html 单调队列是一种严格单调的队列,可以单调递增,也可以单调递减.队 ...

  5. 单调队列优化DP,多重背包

    单调队列优化DP:http://www.cnblogs.com/ka200812/archive/2012/07/11/2585950.html 单调队列优化多重背包:http://blog.csdn ...

  6. bzoj1855: [Scoi2010]股票交易--单调队列优化DP

    单调队列优化DP的模板题 不难列出DP方程: 对于买入的情况 由于dp[i][j]=max{dp[i-w-1][k]+k*Ap[i]-j*Ap[i]} AP[i]*j是固定的,在队列中维护dp[i-w ...

  7. 【HDU 3401 Trade】 单调队列优化dp

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3401 题目大意:现在要你去炒股,给你每天的开盘价值,每股买入价值为ap,卖出价值为bp,每天最多买as ...

  8. Parade(单调队列优化dp)

    题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=2490 Parade Time Limit: 4000/2000 MS (Java/Others)    ...

  9. BZOJ_3831_[Poi2014]Little Bird_单调队列优化DP

    BZOJ_3831_[Poi2014]Little Bird_单调队列优化DP Description 有一排n棵树,第i棵树的高度是Di. MHY要从第一棵树到第n棵树去找他的妹子玩. 如果MHY在 ...

随机推荐

  1. Vultr免费vps注册和使用简易教程

    如果你是站长,寻找托管网站的主机,或者是开发者,需要搭建服务器环境,选购vps是必须的.强烈不推荐国内的vps产品,没有性价比,维护水平又烂,甚至某些国内所谓云主机vps安装后门,监控你的数据.海外v ...

  2. iOS10访问用户权限的描述key值汇总

    https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Ar ...

  3. slam相关知识

    Kinect视觉SLAM技术介绍 http://www.open-open.com/news/view/ce76e2 本文介绍SLAM的历史.理论以及实现的方式,且主要介绍基于视觉(Kinect)的实 ...

  4. php 即时输出

    <?phpset_time_limit(0);ob_end_clean();ob_implicit_flush(1);$i=0;while ( $i>=0 ) { sleep(1); ec ...

  5. Shell脚本常用判断

    -e filename 如果 filename存在,则为真 -d filename 如果 filename为目录,则为真  -f filename 如果 filename为常规文件,则为真 -L fi ...

  6. Oracle字符串操作[转:http://www.cnblogs.com/xd502djj/archive/2010/08/11/1797577.html]

    ORACLE 字符串操作 1 字符串连接   SQL> select 'abc' || 'def' from dual; 'ABC'|------abcdef 2 小写SQL>select ...

  7. JDK下载和安装

    1.下载并安装JDK ,最新版本为1.8.0,官网下载地址:http://www.oracle.com/technetwork/java/javase/downloads/index.html 点击所 ...

  8. C++编写一个简单的DLL

    什么是DLL: 自从微软推出16位的Windows操作系统起,此后每种版本的Windows操作系统都非常依赖于动态链接库(DLL)中的函数和数据,实际上 Windows操作系统中几乎所有的内容都由DL ...

  9. VBS自编写脚本。(实现批量修改文件名且在执行前,备份原有文件夹中的文件)

    '=========================================================================='' VBScript Source File - ...

  10. OpenCV成长之路:图像滤波

    http://ronny.blog.51cto.com/8801997/1394138 OpenCV成长之路:图像滤波 2014-04-11 14:28:44 标签:opencv 边缘检测 sobel ...