【題解】hdu 1401 Solitaire
阿新 • • 發佈:2021-02-08
技術標籤:演算法競賽入門到進階 刷題
目錄
hdu 1401 Solitaire (UVA1724)
題目描述
有一個
8
×
8
8 \times 8
8×8的棋盤,一開始上面有四個棋子,位置是
(
x
1
,
y
1
)
(x_1,y_1)
(x1,y1),
(
x
2
,
y
2
)
(x_2,y_2)
(x2,y2),
(
x
3
,
y
3
)
(x_3,y_3)
(x3,y3),
(
x
4
,
y
4
)
(x_4,y_4)
(x4,y4)。 一個棋子可以上、下、左、右移動,也可以跳過一個棋子,但不能跳過一個以上棋子。 包含多組資料,每組資料給定起始位置和最終位置,問在8步內能不能從起始位置移動到最終位置,能輸出YES
,不能輸出NO
。
輸入輸出樣例
輸入 #1
4 4 4 5 5 4 6 5
2 4 3 3 3 6 4 6
輸出 # 1
YES
方法:雙向BFS
從起始狀態出發搜尋4層,再從最終狀態出發搜尋4層,如果有交集那麼可以在8步內到達。
程式碼:
#include<iostream>
#include<cstdio>
#include<map>
#include <queue>
#include<algorithm>
#define ll long long
using namespace std;
int m[8][8], a[8], dir[4] = {-8, -1, 8, 1}, x, y;
ll ini, ult;
map <ll, int> step_from_ini; //記錄從初始狀態搜尋的層數
map <ll, int> step_from_ult; //從最終狀態搜尋的層數
bool bfs(){
step_from_ini.clear();
step_from_ult. clear();
if(ini == ult) return 1;
queue <ll> q;
q.push(ini);
q.push(ult);
step_from_ini[ini] = 0;
step_from_ult[ult] = 0;
while(!q.empty()){
ll tmp = q.front();
q.pop();
if(step_from_ini[tmp] && step_from_ult[tmp] ) //如果有交集,返回true
return 1;
if(step_from_ini[tmp] >= 4 || step_from_ult[tmp] >= 4) continue; //如果層數大於4,不再繼續搜尋
int b[4];
b[0] = tmp / 1000000;
b[1] = tmp / 10000 % 100;
b[2] = tmp / 100 % 100;
b[3] = tmp % 100; //將long long變成4個棋子對應位置
for(int i = 0; i < 4; i++){ //4個棋子
for(int j = 0; j < 4; j++){ //每次4個方向
int arr = b[i] + dir[j], arrive[4];
ll reach;
int again = 0;
for(int x = 0; x < 4; x++)
if(arr == b[x])
again = 1; //判斷棋子是否重疊
if(arr <= 0 || arr > 64 || b[i] % 8 == 0 && dir[j] == 1 || b[i] % 8 == 1 && dir[j] == -1) //判斷是否越界
continue;
arrive[i] = arr;
if(again){ //如果重疊,判斷是否能向前進方向再進一步(即跨過一個棋子)
int out = arr + dir[j];
if(out <= 0 || out > 64 || arr % 8 == 0 && dir[j] == 1 || arr % 8 == 1 && dir[j] == -1)
continue;
arrive[i] = out;
}
for(int x = 0; x < 4; x++)
if(x != i) arrive[x] = b[x];
sort(arrive, arrive + 4);
reach = arrive[0] * 1000000 + arrive[1] * 10000 + arrive[2] * 100 + arrive[3]; //儲存狀態
if(step_from_ini[tmp]) //從ini搜尋而來
if(!step_from_ini[reach]){
step_from_ini[reach] = step_from_ini[tmp] + 1;
q.push(reach);
}
if(step_from_ult[tmp]) //從ult搜尋而來
if(!step_from_ult[reach]){
step_from_ult[reach] = step_from_ult[tmp] + 1;
q.push(reach);
}
}
}
}
return 0;
}
void initial(){
a[0] = m[x - 1][y - 1];
for(int i = 1; i < 8; i++){
cin >> x >> y;
a[i] = m[x - 1][y - 1];
}
sort(a, a + 4);
sort(a + 4, a + 8); //對點的座標進行排序
ini = a[0] * 1000000 + a[1] * 10000 + a[2] * 100 + a[3];
ult = a[4] * 1000000 + a[5] * 10000 + a[6] * 100 + a[7]; //儲存狀態:4個點對應位置組成的long long
}
int main(){
int it = 0;
for(int i = 0; i < 8; i++)
for(int j = 0; j < 8; j++)
m[i][j] = ++it; //預處理m陣列,使得棋盤上每一個點都有唯一確定的值於其對應
while(~scanf("%d%d", &x, &y)){ //注意多組資料
initial();
if(bfs()) cout << "YES" << endl;
else cout << "NO" << endl;
}
}