POJ1475 推箱子 模組化思想

2022-03-17 18:03:26 字數 4088 閱讀 3651

自古逢秋悲寂寥,我言秋日勝春朝。

晴空一鶴排雲上,便引詩情到碧霄。 ——劉禹錫

題目:推箱子

**:推箱子遊戲相信大家都不陌生,在本題中,你將控制乙個人把1個箱子到目的地。

給定一張n行m列的地圖,用字元」.」表示空地,字元」#」表示牆,字元」s」表示人的起始位置,字元」b」表示箱子的起始位置,字元」t」表示箱子的目標位置。

求一種移動方案,使箱子移動的次數最少,在此基礎上再讓人移動的總步數最少。

方案中使用大寫的「ewsn」(東西南北)表示箱子的移動,使用小寫的「ewsn」(東西南北)表示人的移動。

輸入格式

輸入包含多個測試用例。

對於每個測試用例,第一行包括兩個整數n,m。

接下來n行,每行包括m個字元,用以描繪整個n行m列的地圖。

當樣例為n=0,m=0時,表示輸入終止,且該樣例無需處理。

輸出格式

對於每個測試用例,第一行輸出」maze #」+測試用例的序號。

第二行輸入乙個字串,表示推箱子的總體移動過程,若無解,則輸出」impossible.」。

每個測試用例輸出結束後輸出乙個空行。

若有多條路線滿足題目要求,則按照n、s、w、e的順序優先選擇箱子的移動方向(即先上下推,再左右推)。

在此前提下,再按照n、s、w、e的順序優先選擇人的移動方向(即先上下動,再左右動)。

資料範圍

1≤n,m≤20

輸入樣例:

1 7

sb....t

1 7sb..#.t

7 11

###########

#t##......#

#.#.#..####

#....b....#

#.######..#

#.....s...#

###########

8 4....

.##.

.#..

.#..

.#.b

.##s

....

###t

0 0

輸出樣例:
maze #1

eeeee

maze #2

impossible.

maze #3

eennwwwwwweeeeeesswwwwwwwnnn

maze #4

swwwnnnnnneeessssss

這道題有點難,我們不妨可以這樣考慮進行假設:

題意明確要求先保證箱子步數最小,再保證人走的路程最短,並要給出具體方案;

先考慮如何保證箱子步數最小,或者說如何求解這個最小值呢?

考慮狀態(box_x, box_y, man_x, man_y),對於該狀態進行廣度優先搜尋即可。

我們考慮,請試想:該狀態擴充套件時,會擴充套件出什麼呢?箱子顯然不可能向任意方向擴充套件,只有當人在箱子的一側,將其「向前」推到符合題意的位置(無障礙),進行一次擴充套件操作;人的擴充套件可以列舉四個方向,每次擴充套件到沒有障礙的位置時,將新狀態放於隊尾進行擴充套件。

這樣,當箱子處於目標位置即為最小值了。

你做錯了! !

還記得廣度優先搜尋滿足什麼性質嗎?單調性。

那麼,佇列中什麼滿足單調性呢?狀態滿足單調性。那麼,我們剛剛的做法,實際上是以總步數作為關鍵字,總步數單調!

而實際上題目要求箱子移動步數最優的前提下再保證人步數最小值。換言之,箱子移動步數是第一關鍵字,而在此滿足最優的情況下,人作為第二關鍵表示在狀態中了。

那麼,對於每個狀態,我們只能定義關於箱子的位置,而並不能帶上人的座標。

對於人走了多少步,我們可以在對其中進行bfs擴充套件;

總結:對於推箱子這個問題,其實是箱子走迷宮問題,狀態的每一次擴充套件時所需要的人最少步數,恰又是乙個bfs。

大的bfs套著乙個bfs,這便是所謂的「雙重bfs」!

其實,不管題目有多麼複雜,如果每次考慮問題都先整體去考慮,對於細節的求解假定它是可求的,那麼,當大框架大部署確定後,問題便一目了然,無論是演算法設計還是**實現。

**如下:

#include#include#include#include#include#define pii pair //to simplify the questions, we prefer to use pair and make first -> x, second -> y.

#define x first

#define y second

using namespace std;

struct rec

man, box, tg;

//tg -> target

const int max_size = 20 + 10;

const int dx[4] = , dy[4] = ;

const char cdir[5] = , ddir[5] = ; //up 0 down 1 left 2 right 3

queue ans;

bool book[max_size][max_size][4];

bool mat[max_size][max_size];

char map[max_size][max_size];

int n, m;

int d[max_size][max_size], d_man[max_size][max_size][4], f_box[max_size][max_size][4], d_box[max_size][max_size][4];

int f_man[max_size][max_size];

void init()

} return;

}bool valid(int x, int y)

int expand(pii st, pii ed, stack &s)

return d[next.x][next.y];

}q.push(next);

} }return -1;

}void _print(int x, int y, int dir)

return;

} int prev_dir = f_box[x][y][dir], prev_x = x - (dx[dir] + dx[prev_dir]), prev_y = y - dy[dir] - dy[prev_dir];

_print(x - dx[dir], y - dy[dir], prev_dir);

mat[x - dx[dir]][y - dy[dir]] = true;

expand(make_pair(prev_x, prev_y), make_pair(x - (dx[dir] * 2), y - (dy[dir] * 2)), s);

memset(mat, false, sizeof(mat));

while(!s.empty())

ans.push(cdir[dir]);

return;

}bool bfs()

); book[box.x][box.y][k] = true;

num = 0;

} while(!q.empty())

continue;

}book[next.x][next.y][k] = true;

f_box[next.x][next.y][next.dir] = now.dir;

num = d_box[now.x][now.y][now.dir] + 1;

cnt = d_man[now.x][now.y][now.dir] + tmp;

if(next.x == tg.x && next.y == tg.y)

else if(cnt < d_man[tg.x][tg.y][tg.dir]) tg.dir = next.dir;}}

q.push(next);

} }if(tg.dir != -1)

return false;

}int main()

init();

if(bfs())

puts("");

} else puts("impossible.");

puts("");

} return 0;

}

推箱子遊戲

大一寒假 1.寫 時我犯了乙個很大的錯誤 不然早就搞定了 把 與 混淆了 大忌啊 2.這裡實現了數位化編碼 3.上72 下80 左75 右77 4.特殊圖形可以到qq拼音符號裡獲取 include include include define x 1 人的位置 define y 5 define n...

推箱子遊戲

本專案開發環境為vs2017 c 對推箱子遊戲的觀察可以發現,該遊戲就是在乙個頁面對進行移動的操作。因此可以定義乙個二維陣列map,進行初始化。0 空地 1 牆壁 3 箱子的目的地 4 箱子 6 人 7 箱子與目的地重合 9 人在箱子目的地。如下 include include include in...

C實現推箱子

推箱子遊戲編寫思路總結 1.顯示遊戲地圖 2.顯示小人移動的方向 3.移動小人 第一 簡單的介面輸出時可以用指標陣列,指標陣列map中含十個指標map 0 map 1 map 9 分別是這是個字串的起始位址 char map row 但最後改變位置時不太方便,還是使用c以二維陣列輸出比較簡潔。第二 ...