1. 程式人生 > 其它 >【題解】hdu 1401 Solitaire

【題解】hdu 1401 Solitaire

技術標籤:演算法競賽入門到進階 刷題

目錄

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; } }