P1379 八數碼難題(雙端佇列)
阿新 • • 發佈:2020-08-07
雙端佇列
用單佇列實現雙端佇列時需要注意標記陣列是不一樣的。我們讓我們想要的第一個佇列用\(1\)來標記,第二個用\(2\)來標記,那麼當他們碰面的時候也就是\(1+2=3\)的時候就是我們想要的答案。
-
雙端佇列開陣列來記錄權值。
-
標記要標記傳標記\(vis[now] = vis[cur];\)。
-
雙端佇列對走過點的判斷條件是\(vis\)相同。
思路
將\(3\times 3\)陣列化為一位陣列來儲存,移動的時候再轉換為\(3\times 3\)陣列。
需要特判還沒入隊就相等的情況。
交換後記得交換回來。
如果這個點和\(cur\)的\(vis\)相同記得換回地圖(\(swap\)
#include <bits/stdc++.h> #define INF 0x3f3f3f3f #define DOF 0x7f7f7f7f #define endl '\n' #define mem(a, b) memset(a, b, sizeof(a)) #define debug(case, x) cout << case << " : " << x << endl #define open freopen("ii.txt", "r", stdin) #define close freopen("oo.txt", "w", stdout) #define IO \ ios::sync_with_stdio(false); \ cin.tie(0); \ cout.tie(0) #define pb push_back using namespace std; #define int long long #define lson rt << 1 #define rson rt << 1 | 1 typedef long long ll; typedef pair<int, int> pii; typedef pair<long long, long long> PII; const int maxn = 1e6 + 10; int str; int dir[4][2] = {1, 0, 0, 1, -1, 0, 0, -1}; int mt[5][5]; map<int,int>dis; map<int,int>vis; void bfs() { queue<int>q; int flag = 123804765; if(str==flag){ cout<<0<<endl; return ; } q.push(str); q.push(flag); vis[str] = 1; vis[flag] = 2;dis[str]=0,dis[flag]=0; while(!q.empty()) { int now = q.front(); int cur = now; q.pop(); int sx=1, sy=1; for(int i = 3; i >= 1; --i) { for(int j = 3; j >= 1; --j) { mt[i][j] = now % 10; now /= 10; if(mt[i][j]==0)sx = i, sy = j; } } for(int i = 0; i < 4; ++i) { int xx = sx + dir[i][0], yy = sy + dir[i][1]; if(xx < 1 || xx > 3 || yy < 1 || yy > 3)continue; swap(mt[sx][sy], mt[xx][yy]); now = 0; for(int j = 1; j <= 3; ++j) { for(int i = 1; i <= 3; ++i) { now = now * 10 + mt[j][i]; } } if(vis[cur] == vis[now]) { swap(mt[sx][sy], mt[xx][yy]); continue; } if(vis[cur] + vis[now] == 3) { cout << dis[cur]+dis[now]+1 << endl; return ; } dis[now]=dis[cur]+1; vis[now] = vis[cur]; q.push(now); swap(mt[sx][sy],mt[xx][yy]); } } } signed main() { cin >> str; bfs(); }