1.入门级
注意BFS是向4个方向同时扩展,搜索的一定是最短路径。如果把用掉的点标记:
2 2 3
S.
D.
这组数据用BFS只能搜到1,不能搜到3的路径。BFS不知道怎么剪枝才能不超时。
DFS解法:

/*------------------------------------------------ @file hdu1010 解题: 优化: @author fripSide @date 2014/02/16 ------------------------------------------------*/ #include <cstdio> #include <cmath> #include <memory.h> using namespace std; char maze[9][9]; int go[4][2] = {{1,0}, {-1,0}, {0,1}, {0,-1}}; int n, m, t; int sx, sy, ex, ey; bool DFS(int x, int y, int cnt) { if (cnt == t) { if (x == ex && y == ey) { return true; } return false; } else if (cnt > t) { return false; } if (abs(x - ex) + abs(y - ey) > t - cnt) { return false; } for (int i = 0; i < 4; ++i) { int cx = x + go[i][0]; int cy = y + go[i][1]; if (cx >= 0 && cx < n && cy >= 0 && cy < m && maze[cx][cy] != 'X') { maze[cx][cy] = 'X'; if (DFS(cx, cy, cnt + 1)) { return true; } maze[cx][cy] = '.'; } } return false; } int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); #endif while (scanf("%d%d%d", &n, &m, &t) != EOF && n != 0) { int r = 0; for (int i = 0; i < n; ++i) { scanf("%s", maze[i]); for (int j = 0; j < m; ++j) { if (maze[i][j] == 'S') { sx = i; sy = j; } else if (maze[i][j] == 'D') { ex = i; ey = j; } else if (maze[i][j] == '.') { r++; } } } if (r + 1 < t || (sx + sy + ex + ey + t) % 2 == 1) { puts("NO"); continue; } maze[sx][sy] = 'X'; puts(DFS(sx, sy, 0) ? "YES" : "NO"); } return 0; }
这个解法100+ms,优化:
1.扩大maze,避免边界判断(可以优化到50ms以内)
2.一开始就剪枝
DFS解法:

/*------------------------------------------------ @file hdu1241 解题: @author fripSide @date 2014/02/18 ------------------------------------------------*/ #include <cstdio> #include <memory.h> char maze[105][105]; bool mark[105][105]; int go[8][2] = {{1,0}, {-1,0}, {0,1}, {0,-1}, {1,1}, {1,-1}, {-1,1}, {-1,-1}}; void DFS(int x, int y) { for (int i = 0; i < 8; ++i) { int cx = x + go[i][0]; int cy = y + go[i][1]; if (maze[cx][cy] == '@' && !mark[cx][cy]) { mark[cx][cy] = true; DFS(cx, cy); } } } int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); #endif int n, m; while (scanf("%d%d", &n, &m) != EOF && n != 0) { memset(maze, '*', sizeof maze); //避免判断边界 memset(mark, false, sizeof mark); for (int i = 1; i <= n; ++i) { scanf("%s", maze[i] + 1); } int ans = 0; for (int i = 1; i <= n; ++i) { for (int j = 1; j <= m; ++j) { if (maze[i][j] == '@' && !mark[i][j]) { DFS(i, j); ans++; } } } printf("%d ", ans); } return 0; }
注意:BFS求出的路径是步数最少,而本题中经过X时间要+2,所以在选择路径时应该用优先权队列。
优先权队列实现的两种方法:
用小顶堆:

struct N { int x, y; int t; bool operator > (const N & n) const { return t > n.t; } }; priority_queue<N,vector<N>, greater<N> > Q;
或者:直接用大顶堆

struct N { int x, y; int t; bool operator < (const N & n) const { return t > n.t;//让<返回逆序的结果 } }; priority_queue<N> Q;

/*------------------------------------------------ @file hdu1241t 解题: @author fripSide @date 2014/02/18 ------------------------------------------------*/ #include <cstdio> #include <memory.h> #include <queue> #include <functional> #include <vector> using namespace std; char maze[205][205]; bool mark[205][205]; int go[4][2] = {{1,0},{-1,0},{0,1},{0,-1}}; struct N { int x, y; int t; bool operator > (const N & n) const { return t > n.t; } }; priority_queue<N, vector<N>, greater<N> > Q; int BFS() { while (!Q.empty()) { N cnt = Q.top(); Q.pop(); for (int i = 0; i < 4; ++i) { int cx = cnt.x + go[i][0]; int cy = cnt.y + go[i][1]; if (mark[cx][cy]) { continue; } if (maze[cx][cy] == 'a') { return cnt.t + 1; } if (maze[cx][cy] != '#') { N tmp; tmp.x = cx; tmp.y = cy; if (maze[cx][cy] == '.') { tmp.t = cnt.t + 1; } else { tmp.t = cnt.t + 2; } Q.push(tmp); mark[cx][cy] = true; } } } return -1; } int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); #endif int n, m; while (scanf("%d%d", &n, &m) != EOF) { memset(maze, '#', sizeof maze); for (int i = 1; i <= n; ++i) { scanf("%s", maze[i] + 1); maze[i][m + 1] = '#'; } N tmp; int maxn = -1; for (int i = 1; i <= n; ++i) { for (int j = 1; j <= m; ++j) { if (maze[i][j] == 'r') { memset(mark, false, sizeof mark); while (!Q.empty()) { Q.pop(); } mark[i][j] = true; tmp.t = 0; tmp.x = i; tmp.y = j; Q.push(tmp); int ans = BFS(); if (ans != -1 && ans < maxn || maxn == -1) { maxn = ans; } } } } if (maxn == -1) { puts("Poor ANGEL has to stay in the prison all his life."); } else { printf("%d ", maxn); } } return 0; }
hdu 1026 Ignatius and the Princess I
注意:
1: 首先知道 广搜 + 优先队列。因为要求出时间最短,且从队列里先出来的不一定最优(仅当所有的点花的时间相同时是最优)。
2: 路径的处理:由于搜索时,每一个节点可以推出多个节点(一对多关系):这些后继中只有一个是对的;
而反过来,每个节点的前驱只有一个。 所以可以用前驱保存关系,待会再从末尾到开始反着找关系。或者倒着搜索。
倒着搜索:

/*------------------------------------------------ @file hdu1026 解题: 广度优先的时候,一个点的后继结点有好几种可能,但前驱结点只有一个。 @author fripSide @date 2014/02/18 ------------------------------------------------*/ #include <cstdio> #include <memory.h> #include <queue> using namespace std; char maze[105][105]; int go[4][2] = {{1,0},{-1,0},{0,1},{0,-1}}; struct N { int x, y; int t; bool operator < (const N& n) const { return t > n.t; } }; priority_queue<N> Q; //小顶堆 struct P { int nx, ny; int fight; } path[105][105]; //记录路径 int BFS() { while (!Q.empty()) { N cnt = Q.top(); Q.pop(); if (cnt.x == 1 && cnt.y == 1) { return cnt.t; } for (int i = 0; i < 4; ++i) { int cx = cnt.x + go[i][0]; int cy = cnt.y + go[i][1]; if (maze[cx][cy] != 'X') { N tmp; tmp.x = cx; tmp.y = cy; tmp.t = cnt.t + 1; int fight = 0; if (maze[cx][cy] != '.') { fight = maze[cx][cy] - '0'; } tmp.t += fight; Q.push(tmp); maze[cx][cy] = 'X'; path[cx][cy].nx = cnt.x; path[cx][cy].ny = cnt.y; path[cx][cy].fight = fight; } } } return -1; } int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); #endif int n, m; while (scanf("%d%d", &n, &m) != EOF) { memset(maze, 'X', sizeof maze); for (int i = 1; i <= n; ++i) { scanf("%s", maze[i] + 1); maze[i][m + 1] = 'X'; } while (!Q.empty()) { Q.pop(); } N tmp; tmp.x = n; tmp.y = m; tmp.t = 0; Q.push(tmp); if (maze[n][m] != '.') { path[n][m].fight = maze[n][m] - '0'; } maze[n][m] = 'X'; int ans = BFS(); if (ans == -1) { puts("God please help our poor hero."); } else { ans += path[n][m].fight; printf("It takes %d seconds to reach the target position, let me show you the way. ", ans); int pos = 0; int x = 0; int y = 0; while (pos < ans) { int cx = path[x + 1][y + 1].nx - 1; int cy = path[x + 1][y + 1].ny - 1; printf("%ds:(%d,%d)->(%d,%d) ", ++pos, x, y, cx, cy); for (int i = 0; i < path[cx + 1][cy + 1].fight; ++i) { printf("%ds:FIGHT AT (%d,%d) ", ++pos, cx, cy); } x = cx; y = cy; } } puts("FINISH"); } return 0; }