HDU 1254 推箱子 C++優先佇列+bfs
問題描述
題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=1254
推箱子是一個很經典的遊戲.今天我們來玩一個簡單版本.在一個M*N的房間裡有一個箱子和一個搬運工,搬運工的工作就是把箱子推到指定的位置,注意,搬運工只能推箱子而不能拉箱子,因此如果箱子被推到一個角上(如圖2)那麼箱子就不能再被移動了,如果箱子被推到一面牆上,那麼箱子只能沿著牆移動.
現在給定房間的結構,箱子的位置,搬運工的位置和箱子要被推去的位置,請你計算出搬運工至少要推動箱子多少格.
輸入格式
輸入資料的第一行是一個整數T(1<=T<=20),代表測試資料的數量.
然後是T組測試資料,每組測試資料的第一行是兩個正整數M,N(2<=M,N<=7),代表房間的大小.
然後是一個M行N列的矩陣,代表房間的佈局,其中0代表空的地板,1代表牆,2代表箱子的起始位置,3代表箱子要被推去的位置,4代表搬運工的起始位置.
輸出格式
對於每組測試資料,輸出搬運工最少需要推動箱子多少格才能幫箱子推到指定位置,如果不能推到指定位置則輸出-1.
樣例輸入
1
5 5
0 3 0 0 0
1 0 1 4 0
0 0 1 0 0
1 0 2 0 0
0 0 0 0 0
樣例輸出
4
思路
求最短時間一般用的是bfs。但這道題用普通的bfs會WA,因為要求的最短路是推動箱子的最小步數,而普通的bfs是搬運工移動的最小次數,而移動的次數少不一定能代表推動箱子次數少,例如下面這組資料:
1
3 5
1 1 4 0 0
0 2 0 0 0
0 3 0 0 0
若用普通的bfs執行這組資料,得到的結果是5,而用優先佇列+bfs執行結果是3,因為此時推動箱子次數少,但搬運工走的步數要多(若想要只推動3次箱子則必須繞幾個彎才能達到終點)。故普通的bfs會WA。
注意事項
雖然優先佇列可以用C++的STL模板庫裡的priority_queue,如下:
priority_queue<node> w; //這是元素大的排前面,若想要元素小的排前面則要用priority_queue<node,vector<int>,greater<int> > w;
但是需要過載一個<,並注意在前面加上friend,如下:
friend inline bool operator < (node a,node b) {
return a.t>b.t; //注意符號不要寫反,是大於號
}
每次bfs完都要把佇列裡剩下的元素全部彈出,如下:
while(!w.empty()) w.pop();
bfs函式
首先要用一個數組來記錄狀態。這裡由於人和箱子的位置都要記錄,所以應用一個四維陣列來記錄(其實由於n和m不超過7,二維陣列,十位表示橫座標,個位表示縱座標也是可以的)。
當人碰到箱子的時候箱子就向同樣的方向移動一次。
其他和普通的bfs是一樣的,就不詳細說了。
搜完所有狀態後若仍無解則返回-1。
程式碼
#include<stdio.h>
#include<cstring>
#include<queue>
using namespace std;
const int Size=13;
const int dx[] = {1,0,0,-1};
const int dy[] = {0,1,-1,0};
int map[Size][Size];
bool memory[Size][Size][Size][Size]; //判重陣列
int m,n,x1,y1,x2,y2,x3,y3;
struct node { //節點
int x,y;
int bx,by;
int t;
friend inline bool operator < (node a,node b) {
return a.t>b.t;
}
};
priority_queue<node>w;
void push_queue(int x,int y,int bx,int by,int time) {
node a;
a.x=x,a.y=y,a.bx=bx,a.by=by,a.t=time;
w.push(a);
memory[x][y][bx][by]=true;
}
int read() { //快速讀入函式
int x=0,f=1;
char ch=getchar();
while(ch<'0' || ch>'9') {
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9') {
x=10*x+ch-'0';
ch=getchar();
}
return x*f;
}
void init() { //初始化
memset(memory,0,sizeof(memory));
m=read(),n=read();
for(int i=1; i<=m; i++) {
for(int j=1; j<=n; j++) {
map[i][j]=read();
switch(map[i][j]) {
case 2: x3=i;y3=j;break;
case 3: x2=i;y2=j;break;
case 4: x1=i;y1=j;break;
default:break;
}
}
}
while(!w.empty()) w.pop(); //將佇列裡剩下的元素彈出佇列
push_queue(x1,y1,x3,y3,0);
}
inline bool judge(int x,int y) { //判斷(x,y)滿不滿足入隊要求
return (x>=1 && y>=1 && x<=m && y<=n && map[x][y]!=1);
}
int bfs() {
node now,nxt;
int nx,ny,bx,by,nt;
while(!w.empty()) {
now=w.top();
w.pop();
if(map[now.bx][now.by]==3) return now.t;
for(int i=0; i<4; i++) {
nx=now.x+dx[i],ny=now.y+dy[i];
bx=now.bx,by=now.by;
nt=now.t;
if(judge(nx,ny) && (!memory[nx][ny][bx][by])) {
if(nx==bx && ny==by) {
bx+=dx[i],by+=dy[i],nt++;
if(!judge(bx,by)||memory[nx][ny][bx][by])continue;
push_queue(nx,ny,bx,by,nt);
} else {
push_queue(nx,ny,bx,by,nt);
}
}
}
}
return -1;
}
int main() {
int t=read(),out;
while(t--) {
init();
printf("%d\n",bfs());
}
return 0;
}
相關推薦
HDU 1254 推箱子 C++優先佇列+bfs
問題描述 題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=1254 推箱子是一個很經典的遊戲.今天我們來玩一個簡單版本.在一個M*N的房間裡有一個箱子和一個搬運工,搬運工的工作就是把箱子推到指定的位置,注意,搬運
hdu 1254 推箱子 (BFS)
#include <iostream> #include <queue> #include <algorithm> using namespace std; const int maxn = 10; int a[maxn][maxn]; int n, m; i
hdu 1254 推箱子 BFS
#include <map> #include <vector> #include <queue> #include <cmath> #include <cstdio> #include <string> #include <cst
hdu 1254 推箱子 雙層bfs
#include <cstdio> #include <cstring> #include <cmath> #include <queue> #include <iostream> #include <alg
HDU 1254 推箱子 解題報告
Description 推箱子是一個很經典的遊戲.今天我們來玩一個簡單版本.在一個M*N的房間裡有一個箱子和一個搬運工,搬運工的工作就是把箱子推到指定的位置,注意,搬運工只能推箱子而不能拉箱子,因此如果箱子被推到一個角上(如圖2)那麼箱子就不能再被移動了
【1254 HDU】推箱子
題目:點選開啟題目連結 Problem Description 推箱子是一個很經典的遊戲.今天我們來玩一個簡單版本.在一個M*N的房間裡有一個箱子和一個搬運工,搬運工的工作就是把箱子推到指定的位置,注意,搬運工只能推箱子而不能拉箱子,因此如果箱子被推到一個角上(如圖2)那麼箱子就不能再被移動
網易2017遊戲研發面試題 —— 推箱子(廣搜BFS判斷)
#include<iostream> #include <queue> #include <map> using namespace std; typedef pair<int, int> point; typedef pair<point,
[queue] c++優先佇列(priority_queue)用法詳解
要包含標頭檔案#include <queue> 優先佇列具有佇列的所有特性,包括基本操作,只是在這基礎上添加了內部的一個排序,它本質是一個堆實現的 定義:priority_queue<Type, Container, Functional> T
hdu 5470 Typewriter 字尾自動機+優先佇列優化DP
這道題是用的是字尾自動機 + 優先佇列優化DP。 正常考慮DP的話,暴力DP需要O(n^2)的複雜度,不可行。這道題用優先佇列優化DP可以到O(n)的複雜度。 用dp【i】表示寫出前i個字元需要的cost。則求dp【i】的時候有兩種轉移情況 ①:dp【i-1】+co
1726 優先佇列bfs
#include<cstdio> #include<iostream> #include<cmath> #include<cstring> #includ
霍夫曼編碼(C++ 優先佇列)
霍夫曼編碼 一般採用字首編碼 -- -- 對字符集進行編碼時,要求字符集中任一字元的編碼都不是其它字元的編碼的字首,這種編碼稱為字首(編)碼。 演算法思想: 構造哈夫曼樹非常簡單,將所有的節點放到一個佇列中,用一個節點替換兩個頻率最低的節點,新節點的頻率就是這兩個節點的頻率之和。這
POJ 2449 - Remmarguts' Date - [第k短路模板題][優先佇列BFS]
題目連結:http://poj.org/problem?id=2449 Time Limit: 4000MS Memory Limit: 65536K Description "Good man never makes girls wait or breaks an appointment!" sa
探究C++優先佇列
結構 我們平時會用到一種很高效的資料結構:優先佇列,用法和用途就不在這裡講了,那麼它的內部到底是怎麼工作的呢?為了探究,我寫了一個仿函式,用來顯示它的每次比較: struct itn{ bool operator()(int a,int b) { printf("%d
C++ 優先佇列 priority_queue 的基本使用方法【定義優先順序】
之前是轉載的,可是覺得那種方式對我不太好用,所以再學一個其他的優先順序排序方式; 結構體元素的優先順序排序方式: #include<cstdio> #include<queue> using namespace std; pri
C++優先佇列priority_queue的詳細使用方法
說到佇列,我們首先想到就是先進先出,後進後出;那麼何為優先佇列呢,在優先佇列中,元素被賦予優先順序,當訪問元素時,具有最高階優先順序的元素先被訪問。即優先佇列具有最高階先出的行為特徵。 優先佇列在標頭檔案#include 中; 其宣告格式為:priority_queue ans;//
HDU 5360 Hiking (貪心+優先佇列)
There are n soda conveniently labeled by 1,2,…,n. beta, their best friends, wants to invite some soda to go hiking. The i-th soda will go hiking if the
C++優先佇列解決哈夫曼(Huffmam)編碼問題 (STL priority_queue)
Huffman樹和Huffman編碼的概念在此不再贅述了。 實現Huffman樹的難點在於如何從節點集合中找到兩個權最小的節點並將其合併。 STL中的priority_queue基於小頂堆實現,能滿足較快找到權重最小兩節點的要求。 1.priority_queue的基本用法
1254 推箱子
推箱子是一個很經典的遊戲.今天我們來玩一個簡單版本.在一個M*N的房間裡有一個箱子和一個搬運工,搬運工的工作就是把箱子推到指定的位置,注意,搬運工只能推箱子而不能拉箱子,因此如果箱子被推到一個角上(如圖2)那麼箱子就不能再被移動了,如果箱子被推到一面牆上,那麼箱子只能
1254 推箱子(標記狀態,思路)
推箱子是一個很經典的遊戲.今天我們來玩一個簡單版本.在一個M*N的房間裡有一個箱子和一個搬運工,搬運工的工作就是把箱子推到指定的位置,注意,搬運工只能推箱子而不能拉箱子,因此如果箱子被推到一個角上(如圖2)那麼箱子就不能再被移動了,如果箱子被推到一面牆上,那麼箱子只能沿著牆移
C++ 優先佇列的使用
首先看下優先佇列的STL原始碼: class priority_queue { protected: _Sequence c; ///容