HDU 1026 Ignatius and the Princess I 迷宫范围内的搜索剪枝问题
這個(gè)問(wèn)題是一個(gè)典型的類型的問(wèn)題迷宮廣泛的搜索。
在網(wǎng)上看到了很多解決方案。
沒(méi)什么解決問(wèn)題的分析報(bào)告,不指出其中的關(guān)鍵點(diǎn)。代碼更像是一大抄。一些分析師也有很大的文章分析。只是不要全部命中關(guān)鍵,什么是廣泛而深刻的,甚至搜索發(fā)現(xiàn),在分析差異。為什么快速搜索寬像,什么樣的風(fēng)暴喊搜索,都錯(cuò)了。代碼都是抄過(guò)的。
通過(guò)一大段的時(shí)間研究,最終搞通了。
本題盡管能夠說(shuō)是廣搜。可是當(dāng)中的關(guān)鍵卻是剪枝法。為什么呢?
由于迷宮并不能簡(jiǎn)單地廣搜就能搜索出全部路徑的,甚至僅僅要迷宮大點(diǎn)就不能搜索出是否有路徑。假設(shè)沒(méi)有條件剪枝的情況下。不信,你嚴(yán)格寫一個(gè)廣搜搜索一下迷宮路徑看看。當(dāng)然你寫了個(gè)錯(cuò)誤的廣搜。自然得出錯(cuò)誤的答案了。
常見(jiàn)的錯(cuò)誤是一格一格地?cái)U(kuò)展迷宮就以為是迷宮的廣搜了,錯(cuò)!
真正的廣搜是須要把迷宮建圖。然后廣搜。
事實(shí)上真正的關(guān)鍵是剪枝:
剪枝思考就是要思考什么時(shí)候應(yīng)該擴(kuò)展到下一格?是否合法的格子就一定能夠擴(kuò)展?當(dāng)然不是,是須要依據(jù)題意剪枝。本題的題意是求用時(shí)最小的路徑。故此能夠由此想到應(yīng)該是以時(shí)間比較來(lái)決定是否須要擴(kuò)展到下一格的。
即下一格有可能找到更加優(yōu)的解就擴(kuò)展。否則就不擴(kuò)展。
這樣一剪枝之后。就能夠使用所謂的廣搜了。
那么為什么本題。或者能夠說(shuō)本題題型的題目不能夠使用深搜呢?
由于上面的剪枝條件是每一層去剪枝的,假設(shè)使用深搜,那么這種剪枝條件就無(wú)法用上了。
另一種做法就是利用優(yōu)先隊(duì)列。優(yōu)先擴(kuò)展當(dāng)前最小用時(shí)的格子。那么就能夠不用反復(fù)搜索下一格了。這也是利用了上面的剪枝思想。
只是僅僅要理解了上面的關(guān)鍵剪枝點(diǎn),那么這種題目都能夠隨心所欲地攻克了。
至于本題的記錄路徑就是編程功底的測(cè)試了,不用說(shuō)什么思路了。不會(huì)的僅僅能說(shuō)編碼能力不行了。
或許也有不懂分析的人也把代碼敲對(duì)了,或許是他運(yùn)氣不錯(cuò)。或許是他真的是天才級(jí)的人物!
反正幾率都非常低,最大幾率還是他的代碼是抄來(lái)的。
理解不了這點(diǎn)的。就沒(méi)有透切理解這個(gè)問(wèn)題。 */ namespace IgnatiusandthePrincessI1026 { const int MAX_N = 101; char Maze[MAX_N][MAX_N]; int dx[] = {-1, 0, 1, 0}, dy[] = {0, -1, 0, 1}; struct Node { int sec, x, y; Node *p; }; Node mazeRec[MAX_N][MAX_N]; int N, M; inline bool isLegal(int r, int c) { return 0<=r && 0<=c && r<N && c<M && Maze[r][c] != 'X'; } inline int getSec(int r, int c) { if (Maze[r][c] == '.') return 1; return Maze[r][c] - '0' + 1; } void getPath() { for (int i = 0; i < N; i++) { for (int j = 0; j < M; j++) { mazeRec[i][j].sec = INT_MAX; mazeRec[i][j].x = i, mazeRec[i][j].y = j; mazeRec[i][j].p = NULL; } } queue<Node *> qu; Node *p = &mazeRec[N-1][M-1]; //注意計(jì)算錯(cuò)誤:p->sec = Maze[N-1][M-1] or = getSec(N-1, M-1) p->sec = getSec(N-1, M-1)-1;//終點(diǎn)也可能是有敵人,起點(diǎn)規(guī)定了無(wú)敵人 qu.push(p); while (!qu.empty()) { p = qu.front(); qu.pop(); for (int i = 0; i < 4; i++) { int tx = p->x + dx[i], ty = p->y + dy[i]; if (!isLegal(tx, ty)) continue; int sec = getSec(tx, ty); Node *tmp = &mazeRec[tx][ty]; if (p->sec+sec < tmp->sec) { tmp->sec = p->sec+sec; tmp->p = p; qu.push(tmp); } /* 關(guān)鍵理解:僅僅有當(dāng)下一個(gè)格子更新了最小值的時(shí)候才須要擴(kuò)展到這個(gè)格子。否則就不須要擴(kuò)展到這個(gè)格子。這個(gè)也是相當(dāng)于廣搜的剪枝點(diǎn)。
理解不了這點(diǎn)的,就沒(méi)有透切理解這個(gè)問(wèn)題。 */ /*各種錯(cuò)誤教訓(xùn)! qu.push(tmp); tmp.vis = true; //錯(cuò)誤多個(gè)else。邏輯錯(cuò)誤else tmp->vis = true //Maze[tx][ty] = 'X'; tmp.sec = p.sec+sec; tmp.p = &mazeRec[p.x][p.y]; //錯(cuò)誤:tmp->p = p; //錯(cuò)誤:tmp->sec = min(tmp->sec, p->sec+sec);*/ } } } int main() { while (~scanf("%d %d", &N, &M)) { while (getchar() != '\n'); for (int i = 0; i < N; i++) { gets(Maze[i]); } getPath(); Node *p = &mazeRec[0][0]; if (p->sec == INT_MAX) puts("God please help our poor hero."); else { printf("It takes %d seconds to reach the target position, let me show you the way.\n", p->sec); int s = 1; for (; p->p; p = p->p) { int x = p->p->x, y = p->p->y; printf("%ds:(%d,%d)->(%d,%d)\n", s++, p->x, p->y, x, y); if (Maze[x][y] == '.') continue; int fig = Maze[x][y] - '0';//錯(cuò)誤少-'0' for (int i = 0; i < fig; i++) { printf("%ds:FIGHT AT (%d,%d)\n", s++, x, y); } } } puts("FINISH"); } return 0; }
版權(quán)聲明:筆者靖心臟。景空間地址:http://blog.csdn.net/kenden23/。只有經(jīng)過(guò)作者同意轉(zhuǎn)載。
轉(zhuǎn)載于:https://www.cnblogs.com/yxwkf/p/4754291.html
總結(jié)
以上是生活随笔為你收集整理的HDU 1026 Ignatius and the Princess I 迷宫范围内的搜索剪枝问题的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Android而一个超级漂亮的日历控件
- 下一篇: JS选中OPTION