原文链接:
AOJ0558
题意:
在H * W的地图上有N个奶酪工厂,分别生产硬度为1-N的奶酪。有一只吃货老鼠准备从老鼠洞出发吃遍每一个工厂的奶酪。老鼠有一个体力值,初始时为1,每吃一个工厂的奶酪体力值增加1(每个工厂只能吃一次),且老鼠只能吃硬度不大于当前体力值的奶酪。
老鼠从当前格走到相邻的无障碍物的格(上下左右)需要时间1单位,有障碍物的格不能走。走到工厂上时即可吃到该工厂的奶酪,吃奶酪时间不计。问吃遍所有奶酪最少用时。
输入:第一行三个整数H(1 <= H <= 1000)、W(1 <= W <=1000)、N(1 <= N <= 9),之后H行W列为地图, “.“为空地, ”X“为障碍物,”S“为老鼠洞, 1-N代表硬度为1-N的奶酪的工厂。
入力例 1
3 3 1
S..
...
..1
出力例 1
4
入力例 2
4 5 2
.X..1
....X
.XX.S
.2.X.
出力例 2
12
入力例 3
10 10 9
.X...X.S.X
6..5X..X1X
...XXXX..X
X..9X...X.
8.X2X..X3X
...XX.X4..
XX....7X..
X..X..XX..
X...X.XX..
..X.......
出力例 3
91
思路:
老鼠初始体力值为1,并且只能吃硬度不大于当前体力值的奶酪,每吃一个奶酪体力值增加1。有N个奶酪,硬度分别为1~N。说明老鼠只能按照1~N的顺序吃。比如有5个奶酪,硬度分别是1、2、3、4、5,老鼠只能按照这个顺序吃,吃完之后的体力值分别为2、3、4、5、6。
看起来复杂的条件实际上降低了搜索难度,只需将递增的数字当做终点逐个搜索,相当于正常的BFS循环N次。
代码:
#include <iostream> #include <stdio.h> #include <deque> using namespace std; const int INF = 0x3f3f3f3f; typedef pair<int, int> P; int h, w, n; int sx, sy; int gx, gy; char cmap[1000][1000]; int goalSum; int goal[10]; int d[1000][1000]; int dx[4] = {-1, 0, 1, 0}; int dy[4] = {0, -1, 0, 1}; int bfs() { int res = 0; deque<P> que; for (int ci = 0; ci < n; ci++) { //要进行n次循环,寻找n次终点,每次步数计入goal[i], 最后累加起来是res for (int i = 0; i < h; i++) { for (int j = 0; j < w; j++) { d[i][j] = INF; } } que.push_back(P(sx, sy)); d[sx][sy] = 0; while(que.size()) { int x = que.front().first; int y = que.front().second; que.pop_front(); if ((int)cmap[x][y] == 49 + ci) { goal[ci] = d[x][y]; sx = x; sy = y; break; } for (int i = 0; i < 4; i++) { int nx = x + dx[i]; int ny = y + dy[i]; if (nx >=0 && nx < h && ny >= 0 && ny < w && cmap[nx][ny] != 'X' && d[nx][ny] == INF) { que.push_back(P(nx, ny)); d[nx][ny] = d[x][y] + 1; } } } que.clear(); res += goal[ci]; } return res; } int main() { cin >> h >> w >> n; for (int i = 0; i < h; i++) { for (int j = 0; j < w; j++) { cin >> cmap[i][j]; if (cmap[i][j] == 'S') { sx = i; sy = j; } } } goalSum = bfs(); cout << goalSum << endl; //不换行会PE return 0; }
- 通常 BFS 使用队列 queue 即可,这里由于多次循环 BFS,每次要清空队列,故用了 STL 的双端队列 deque,clear() 函数用来清空。
- deque 常用函数有:front(), back(), push_front(), push_back(), pop_front(), pop_back()。头尾均可以访问、添加、删除。
- d[x][y]在记录起点到某坐标的步数的同时,还起到标志该点是否被搜索过的作用。
- queue的empty()函数不是用来清空的!是返回该队列是否为空> < (debug了很久_(:зゝ∠)_)