題意:在一個 N*M 的地圖中,每個格子代表一個房間,’#'代表堅不可摧的房間,是不可進入的; '.‘代表脆弱的房間🏠,是可以進入的;’@'代表起點,然後有K個寶物,分別放在了這些脆弱的房間裏面。求從起點開始,拿到所有寶物最小需要的步數(在起點步數爲0,每走一格步數+1)
錯誤思路:需要求最短路,盲猜直接BFS,將寶物的座標用一個map存起來,在struct裏面多加一個 set 來記錄當前路徑中拿到了哪些寶物,當 set.size 和 k 相等的時候,直接輸出答案就完事了。巴特,這個思路有一個不好處理的地方,在實際情況當中或許正解會同一個點走兩次,所以我們不能在剪枝的時候加上vis數組驗證,這樣就會導致大量的點來回走,並且加入隊列,耗費太多空間,就 Memory Limit Exceeded 了。
看看代碼吧🤦♂️:
#include <bits/stdc++.h>
using namespace std;
int n, m, k, x, y;
char mp[105][105];
map <pair<int, int>, bool> ok;
struct Node {
int x, y, step;
set <pair<int, int> > con;
};
queue <Node> q;
int main() {
while(~scanf("%d %d", &n, &m) && n != 0) {
ok.clear();
while(!q.empty()) q.pop();
int stax, stay;
for(int i = 1;i <= n; i++) {
for(int j = 1;j <= m; j++) {
scanf(" %c", &mp[i][j]);
if(mp[i][j] == '@') stax = i, stay = j;
}
}
scanf("%d", &k);
int num = k;
while(k--) {
scanf("%d %d", &x, &y);
ok[make_pair(x, y)] = 1;
}
Node t;
t.x = stax; t.y = stay; t.step = 0;
if(ok[make_pair(stax, stay)] == 1) {
t.con.insert(make_pair(stax, stay));
}
q.push(t);
bool fin = 0;
int ans = -1;
while(!q.empty()) {
Node res = q.front(); q.pop();
for(int i = -1;i <= 1; i++) {
for(int j = -1;j <= 1; j++) {
if((i != 0 && j != 0) || (i == 0 && j == 0)) continue;
int tx = res.x+i, ty = res.y+j, ts = res.step+1;
set <pair<int, int> > tc = res.con;
if(tx > n || tx < 1 || ty > m || ty < 1 || mp[tx][ty] == '#') continue;
Node Push;
Push.x = tx; Push.y = ty; Push.step = ts; Push.con = tc;
if(ok[make_pair(tx, ty)] == 1) {
Push.con.insert(make_pair(tx, ty));
if(num == Push.con.size()) {
ans = ts;
fin = 1;
break;
}
}
q.push(Push);
}
if(fin) break;
}
if(fin) break;
}
printf("%d\n", ans);
}
}
正確思路:爲了避免上述情況,其實可以讓BFS的路徑按照我們自己想要的路線走;因爲這道題目的K值比較小,從起點開始走完所有的點的順序也就不多,四個寶物的走法也就是 這麼多種,這已經是最多的情況了,把這些點可能走的路線全部走一遍,因爲bfs從一個點走到另一個點肯定是最短路徑的,把這幾段的路走的步數加起來就是一種方案,最後答案取最小的就OK了,這裏面用了一個 全排列的函數 ,也就是把從 1 ~ K可以走的全部方案枚舉出來的函數。
#include <bits/stdc++.h>
using namespace std;
int n, m, k, stax, stay;
char mp[105][105];
struct node {
int x, y, step;
node(int a, int b, int c): x(a), y(b), step(c){}
node(){}
} ok[5];
int p[5];
bool meet[105][105];
int chanx[] = {-1, 1, 0, 0};
int chany[] = {0, 0, -1, 1};
int bfs() {
queue <node> q;
q.push(node(stax, stay, 0));
meet[stax][stay] = 1;
int cnt = 1;
while(!q.empty()) {
node t = q.front(); q.pop();
for(int i = 0;i < 4; i++) {
int tx = t.x + chanx[i];
int ty = t.y + chany[i];
int ts = t.step + 1;
if(tx > n || tx < 1 || ty > m || ty < 1 || mp[tx][ty] == '#' || meet[tx][ty]) continue;
bool flag = 0;
if(tx == ok[p[cnt]].x && ty == ok[p[cnt]].y) flag = 1;
if(flag) {
while(!q.empty()) q.pop();
memset(meet, 0, sizeof(meet));
if(cnt == k) return ts;
cnt++;
}
q.push(node(tx, ty, ts));
meet[tx][ty] = 1;
if(flag) break;
}
}
return -1;
}
int main() {
while(~scanf("%d %d", &n, &m) && n) {
for(int i = 1;i <= n; i++) {
for(int j = 1;j <= m; j++) {
scanf(" %c", &mp[i][j]);
if(mp[i][j] == '@') stax = i, stay = j;
}
}
scanf("%d", &k);
int num = 1;
for(int i = 1;i <= k; i++) {
scanf("%d %d", &ok[i].x, &ok[i].y);
p[i] = i;
num *= i;
}
int ans = -1;
while(num--) {
int sum = bfs();
// cout << "sum = " << sum << endl;
if(sum != -1) ans = ans == -1?sum:min(ans, sum);
next_permutation(p+1, p+1+k);
}
printf("%d\n", ans);
}
}