/*
做完这题我打算看《海底总动员》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
#include
#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
//取当前方向的对面方向
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;
}