Stealing Harry Potter's Precious - 狀壓bfs入門
阿新 • • 發佈:2020-09-15
傳送門
給出一個起點,4個終點,要求從起點出發,每個終點都走到的最短距離
一般來說,如果只有一個終點,那麼就直接bfs,但是有4個終點,用狀壓dp
設定一個vis[N][N][1 << 4]來設定記錄
且每一個點存4個變數,x,y,key和step,key表示當前的狀壓情況
那麼不斷進行bfs,如果遇到終點,那麼進行狀壓一下u.key | (1 << (s[xx][yy] - '0'))即可,同時更新key即可
那麼如果說nex.key == (1 << k) - 1,也就是說4個終點都走過了,那麼就直接返回答案即可
第一次遇到狀壓bfs,記錄下,感覺好神奇啊,大霧
#include <iostream> #include <cstdio> #include <cstring> #include <queue> #include <vector> #include <map> #include <set> #include <cmath> #include <stack> #include <algorithm> #include <ctime> using namespace std; #define ll long long const int N = 105; char s[N][N]; int dir[][2] = {1, 0, -1, 0, 0, 1, 0, -1}; int n, m, k; int sx, sy; bool vis[N][N][1 << 4]; // 狀壓陣列 struct Node{ int x, y, key, step; }; bool check(int x, int y){ if(x < 1 || x > n || y < 1 || y > m || s[x][y] == '#') return 0; return 1; } int bfs(){ queue<Node> q; Node now; now.x = sx, now.y = sy; now.step = 0; now.key = 0; q.push(now); while(!q.empty()) { Node u = q.front(); q.pop(); for(int i = 0; i < 4; i++) { int xx = dir[i][0] + u.x; int yy = dir[i][1] + u.y; if(!check(xx, yy)) continue; Node nex; if(s[xx][yy] >= '0' && s[xx][yy] <= '3') { //終點,狀壓一下,再繼承上一個點的資訊 if(!vis[xx][yy][u.key]) { vis[xx][yy][u.key | (1 << (s[xx][yy] - '0'))] = 1; nex.x = xx, nex.y = yy, nex.step = u.step + 1, nex.key = u.key | (1 << (s[xx][yy] - '0')); if(nex.key == (1 << k) - 1) return nex.step; // 點走完了 q.push(nex); } }else { // 普通點,繼承上一個點的資訊 if(!vis[xx][yy][u.key]) { vis[xx][yy][u.key] = 1; nex.x = xx, nex.y = yy, nex.key = u.key, nex.step = u.step + 1; q.push(nex); } } } } return -1; } int main(){ while(~scanf("%d%d", &n, &m)) { if(n == 0 && m == 0) break; bool f = 1; for(int i = 1; i <= n; i++) scanf("%s", s[i] + 1); for(int i = 1; i <= n; i++) { for(int j = 1; j <= m; j++){ if(s[i][j] == '@') sx = i, sy = j; // 起點 } } memset(vis, 0, sizeof(vis)); scanf("%d", &k); for(int i = 0; i < k; i++) { int x, y; scanf("%d%d", &x, &y); if(s[x][y] == '#') f = 0; else if(s[x][y] == '@') { // 把所有的終點設定為相應的數字,方便進行狀壓 s[x][y] = i + '0'; vis[x][y][1 << i] = 1; } else s[x][y] = i + '0'; } if(!f) printf("-1\n"); else { printf("%d\n", bfs()); } } return 0; }