/*
做完這題我打算看《海底總動員》Demo Demo好可愛
用廣搜過的, 主要思路如下:
(1)首先是建圖, 由於輸入給的都是線段, 但是我們平常處理這類問題都是轉換爲網格來做的, 因此需要
將線段轉換爲網格.轉化的方法是對於每個格子,用其左上角點的座標來表示這個格子,如果其左上角點的
座標是[i][j],那麼這個格子就表示爲[i][j].將其四周邊界的四條線段歸這個格子管.即爲每個格子建一
個數組round[i][j][4],第三維的四個位置分別表示這四條線段的類型: 0表示空氣,1表示牆,2表示是一扇
門,這樣這個模型就建立好了.
(2)其次是bfs的起始點選爲Nemo所在的位置,注意要將這個浮點點位置轉化爲格子的座標.轉化的方法很簡
單.對於x座標取整即可,對於y座標取整+1即可,比如Nemo所在位置爲[1.2, 1.3]那麼轉化爲格子的座標即爲:
[1, 2].這個座標即位bfs遍歷的起始點
(3)遍歷的時候如果所走的方向是牆,則不可走.如果是門則將當前總的steps數+1,如果爲空氣,steps數不變.
另外一點就是如何判重.判重不能簡單地記錄有沒有被訪問過,而是需要記錄到當前格子的最小步驟.如果當
前總步驟數小於當前格子的最小步驟數,則更新其最小步驟數並將這個格子加入隊列中.
(4)遍歷的終止位置即爲題目中的出發位置[0, 0]
*/
#include <iostream>
#include <queue>
#define MAX_N 210 //最大限度邊界
using namespace std;
int v[MAX_N + 1][MAX_N + 1]; //v[i][j]表示到格子[i][j]的最小步驟數
int round[MAX_N + 1][MAX_N + 1][4]; //記錄當前格子四面邊界的類型, 0:air 1:wall 2:door
int wn, dn, startXI, startYI, minSteps; //wn:牆的數目,dn:門的數目,起始點對應的格子座標
double startXF, startYF; //起始點的輸入浮點座標
int dirarray[4][2] = {{0, 1}, {0, -1}, {-1, 0}, {1, 0}}; //方向數組,走四個方向對座標的變化
//上:0, 下:1, 左:2, 右:3
//入bfs隊列的元素類型
struct elem
{
//x, y記錄這個格子的座標; dir記錄是從當前格子的哪個方向進入這個格子的,上:0, 下:1, 左:2, 右:3
int x, y, dir, stepnum;
//stepnum記錄到達當前格子所需的步驟數
};
queue<elem> bfsq; //bfs的隊列
//取當前方向的對面方向
void changeDir(int orgignal, int &newDir)
{
if(orgignal == 0) newDir = 1;
else if(orgignal == 1) newDir = 1;
else if(orgignal == 2) newDir = 3;
else newDir = 2;
}
//當斷當前座標是否在合法範圍內
bool inRange(int x, int y)
{
return x >= 0 && x <= 205 && y >= 0 && y <= 205;
}
void bfs()
{
//將Demo的位置入隊列作爲bfs的起始位置
while(!bfsq.empty()) bfsq.pop();
elem curelem, newelem;
curelem.x = startXI; curelem.y = startYI; curelem.dir = -1; curelem.stepnum = 0;
v[startXI][startYI] = 0;
bfsq.push(curelem);
int curx, cury, curdir, cursteps, newx, newy, newdir, newsteps, d;
while(!bfsq.empty())
{
curelem = bfsq.front();
bfsq.pop();
curx = curelem.x; cury = curelem.y; curdir = curelem.dir; cursteps = curelem.stepnum;
//到達出發點
if(curx == 0 && cury == 0)
{
//更新所需位置的最優值
if(cursteps < minSteps)
minSteps = cursteps;
continue;
}
//遍歷當前格子的四個方向,嘗試往這四個方向走
for(d = 0; d < 4; d++)
{
//不能往回走
if(d != curdir)
{
//所走方向不能是牆
if(round[curx][cury][d] != 1)
{
//得到新的格子座標
newx = curx + dirarray[d][0];
newy = cury + dirarray[d][1];
//新座標在合法範圍內
if(inRange(newx, newy))
{
//計算所有方向相對目標格子所在的方位
changeDir(d, newdir);
//門,步驟數+1
if(round[curx][cury][d] == 2)
newsteps = cursteps + 1;
else //空氣,步驟數不變
newsteps = cursteps;
//判斷這個新格子的新狀態是否需要入隊列
if((v[newx][newy] == 0xbf || newsteps < v[newx][newy]) && newsteps < minSteps)
{
v[newx][newy] = newsteps;
newelem.x = newx; newelem.y = newy; newelem.stepnum = newsteps; newelem.dir = newdir;
bfsq.push(newelem);
}
}
}
}
}
}
}
int main()
{
int i, j, x, y, d, t;
while(scanf("%d%d", &wn, &dn) && !(wn == -1 && dn == -1))
{
minSteps = INT_MAX;
memset(v, 12, sizeof(v));
memset(round, 0, sizeof(round));
for(i = 1; i <= wn; i++)
{
scanf("%d%d%d%d", &x, &y, &d, &t);
//輸入的預處理,將線段(牆)轉換爲相應格子對應的四面邊界
if(d == 1)
for(j = y + 1; j <= y + t; j++)
round[x][j][2] = round[x - 1][j][3] = 1;
else
for(j = x; j < x + t; j++)
round[j][y][0] = round[j][y + 1][1] = 1;
}
for(i = 1; i <= dn; i++)
{
scanf("%d%d%d", &x, &y, &d);
//輸入的預處理,將線段(門)轉換爲相應格子的四面邊界方向
if(d == 1)
round[x][y + 1][2] = round[x - 1][y + 1][3] = 2;
else
round[x][y][0] = round[x][y + 1][1] = 2;
}
scanf("%lf%lf", &startXF, &startYF);
//將Demo的位置轉換爲格子座標
startXI = startXF;
startYI = startYF + 1;
//題目中的異常數據
if(startXI < 0 || startXI > 199 || startYI < 0 || startYI > 199)
printf("0/n");
else
{
bfs();
if(minSteps == INT_MAX) printf("-1/n");
else printf("%d/n", minSteps);
}
}
return 0;
}