就我的理解来说这个题,本质上是一个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. NOIP2002-普及组复赛-第二题-级数求和

    题目描述 Description 已知:Sn= 1+1/2+1/3+…+1/n.显然对于任意一个整数K,当n足够大的时候,Sn大于K. 现给出一个整数K(1<=k<=15),要求计算出一个 ...

  2. mysql的存储引擎如何选择

    myisam:如果表对事务要求不高,用时以查询和添加为主,我们考虑myisam存储,如bbs中的发帖表.回复表 innodb:对事务要求高,保存的数据都是重要的数据,我们建议使用innodb,比如订单 ...

  3. css样式表及属性

    CSS(Cascading Style Sheet,叠层样式表),作用是美化HTML网页. /*注释区域*/    此为注释语法 一.样式表 (一)样式表的分类 1.内联样式表 和HTML联合显示,控 ...

  4. ajax传递的数据类型json传递

    $(".del_goods").click(function(){ //删除选中的商品 var clear_data = [];//数组 $("input[name='c ...

  5. 不合法语句 self.contentView.frame.origin.x = x;

    下面的写法是错误的: CGFloat x = self.contentView.frame.origin.x; x = _lastDownX + translation.x; self.content ...

  6. .Net_把文件数据添加到数据库中(面试题)

    一个文本文件含有如下内容: 4580616022644994|3000|赵涛 4580616022645017|6000|张屹 4580616022645090|3200|郑欣夏 上述文件每行为一个转 ...

  7. yii2图片验证码

    控制器LoginController.php <?php namespace backend\controllers; use Yii; use yii\debug\models\search\ ...

  8. 常用 ajax js 表单

    $(function () { /** * 图片点击放大处理 */ $('.mini_img').click(function () { $(this).hide().next().show(); } ...

  9. Jquery EasyUI datagrid后台数据表格生成及分页详解

    由于项目原因,网站后台需要对用户信息进行各种操作,有时还需要进行批量操作,所以首先需要将用户信息展示出来,查了不少资料.发现Jquery EasyUI确实是一个不错的选择,功能强大,文档也比较全面,而 ...

  10. Extjs 树节点操作常用属性

    tree: 树     node:节点 1.全部展开  tree.expandAll(); 2.全部收缩  tree.collapseAll(); 3.得到父节点 node.parentNode 4. ...