1. 程式人生 > >HDU 1254 推箱子 C++優先佇列+bfs

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; ///容