自古逢秋悲寂寥,我言秋日勝春朝。題目:推箱子晴空一鶴排雲上,便引詩情到碧霄。 ——劉禹錫
**:推箱子遊戲相信大家都不陌生,在本題中,你將控制乙個人把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以二維陣列輸出比較簡潔。第二 ...