题解:P2864 [USACO06JAN] The Grove S
题目传送门
题目大意
这道题目言简意赅,就是要我们求以
思路分析
下面介绍 建墙法。
以一个简单的样例为例:
.......
...X...
..XXX..
...XXX.
...X...
......*
最后一棵树为原点,向下建墙。
最后一棵树
注:
如下所示:
.......
...X...
..XXX..
...XXX.
...X...
...|..*
tips
- 墙不能与贝茜重合
- BFS 时注意墙与树 一样不能走。
- BFS 注意边界。
- 统计过的点无需再次访问。
-
墙不能与树重合。
附上 AC 代码
#include<cstdio> #include<iostream> using namespace std; #define ll long long #define INF 0x7f7f7f7f7f ll min(ll a, ll b) {//手打min return a < b ? a : b; } ll r, c; //见题面,r:长 c:宽 char a[100][100]; //地图 ll sx, sy, ltx, lty; //*的坐标,及最后一棵树的坐标 int dx[8] = {-1, -1, -1, 0, 0, 1, 1, 1}, dy[8] = {-1, 0, 1, -1, 1, -1, 0, 1}; //8个方向 ll ans[110][110]; //见前文 ll q[100100][3], h, t; //手打BFS队列 int main() { cin >> r >> c; //读入 for (int i = 1; i <= r; i++) { for (int j = 1; j <= c; j++) { cin >> a[i][j]; if (a[i][j] == '*')sx = i, sy = j; //*坐标 else if (a[i][j] == 'X')ltx = i + 1, lty = j; //最后一棵树的坐标 } } for (int i = 0; i < 110; i++)for (int j = 0; j < 110; j++)ans[i][j] = INF; //ans赋值为最大值 if (ltx == sx && lty == sy) { //特判,墙不能与*重合 bool f = 0; for (int i = 1; i <= r; i++){ for (int j = 1; j <= c; j++){ if (a[i][j] == 'X' && !f) { ltx = i; lty = j; f = 1; break; } } } for (int i = 1; i <= ltx; i++)a[i][lty] = '|'; } for (int i = ltx; i <= r; i++)a[i][lty] = '|'; ll x, y, s, xx, yy; //BFS开始 ans[sx][sy] = 0; t = 1; q[0][0] = sx; q[0][1] = sy; while (h < t) { x = q[h][0], y = q[h][1], s = q[h][2]; //取队首 for (int i = 0; i < 8; i++) { //8个方向搜 xx = x + dx[i], yy = y + dy[i]; //替死鬼 if (ans[xx][yy] != INF)continue; //不重复搜 if ((xx >= 1 && xx <= r && yy >= 1 && yy <= c) && a[xx][yy] == '.') { //边界及能否走 ans[xx][yy] = s + 1; //记入答案 q[t][0] = xx; //入队 q[t][1] = yy; //入队 q[t++][2] = s + 1; //入队 } } h++; //出队 } //BFS结束 cout << min(ans[ltx - 1][lty - 1], min(ans[ltx][lty - 1], ans[ltx + 1][lty - 1])) + min(ans[ltx - 1][lty + 1], min(ans[ltx][lty + 1], ans[ltx + 1][lty + 1])) + 2; //输出答案 return 0; }