ZOJ - 4020 Traffic Light (BFS)

【传送门】http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4020

【题目大意】从起点(sx, sy)出发,要到达(ex , ey)。每次从点(x,y)走的时候要看红绿灯,灯的状态为1时只能左右走,走到(x , y+1)或者 (x , y-1);灯为0的时候只能上下走,走到(x +1, y)或者 (x-1 , y)。现在问能不能从源点走到终点,如果能,输出最少需要走多少步。

  注意(x,y)代表第x行第y列,不是传统意义上的坐标系。

【题解】求最短路一般用BFS,但是与一般的图不同,这里灯的状态是不断变化的,所以允许走的方向也不同。不妨记一个步数t, t % 2 == 1或者0时方向不同,需要入队的点也不同。

  另外有这样一个事实,只要访问过的点,或者说之前已经入过队的点以后都不会再入队,证明如下:

  若过之前经过一个点(x0, y0), 经过若干步骤以后,又回到了(x0, y0),那么经过了多少步呢?把沿途所有点相连,必然构成一个长方形或者一条来回的直线,很显然,他们的周长必然是2的倍数,也就是偶数,因此再到这一点时这个灯的状态和上一次经过时是一样的,所以没有任何意义。当然也可能发生了这样一个情况:主人公会在这个矩形中循环走动或者在这条线段来回走动,均无法到达终点。

 

【代码】

#include <iostream>
#include <cstring>
#include <string>
#include <queue>
#include <vector>
using namespace std;

struct Node
{
    //点的坐标  走过的步数 
    int x, y, step;
};

int dic1[4] = { 1,-1,0,0 };
int dic2[4] = { 0,0,-1,1 };

vector<vector<int> >maps;
vector<vector<bool> >vis;

int sx, sy, ex, ey;
int state;
int n, m;

//判断点是否能够入队 
bool judge(int x, int y)
{
    if (x > 0 && x <= n && y> 0 && y <= m && vis[x][y] == 0)
    {
        return true;
    }
    return false;
}

//BFS求最短路 
int bfs(Node s)
{
    queue <Node> Q;
    Q.push(s);
    Node p, q;
    vis[s.x][s.y] = true;
    
    while (!Q.empty())
    {
        p = Q.front();
        Q.pop();
        //如果已经到达终点就直接返回步数即可 
        if (p.x == ex && p.y == ey)
        {
            return p.step;
        }
        state = maps[p.x][p.y];
        //看看走到这一点共走了多少步,奇数步需要反转灯的状态,偶数步相当于不用反转 
        if ((p.step) % 2 == 1)
        {
            if (state == 1)
            {
                state = 0;
            }
            else
            {
                state = 1;
            }
        }
        //看这一点的状态(0,1) 确定能走到那两个点,将能到达的点入队 
        if (state == 0)
        {
            for (int i = 0; i<2; i++)
            {
                q.x = p.x + dic1[i];
                q.y = p.y + dic2[i];

                if (judge(q.x, q.y) == true)
                {
                    vis[q.x][q.y] = true;
                    q.step = p.step+1;
                    Q.push(q);
                }
            }
        }
        else if (state == 1)
        {
            for (int i = 2; i<4; i++)
            {
                q.x = p.x + dic1[i];
                q.y = p.y + dic2[i];

                if (judge(q.x, q.y) == true)
                {
                    vis[q.x][q.y] = true;
                    q.step = p.step + 1;
                    Q.push(q);
                }
            }
        }
    }
    return -1;
}
int main()
{
    ios::sync_with_stdio(false); 
    int cas;
    cin >> cas;
    while (cas--)
    {
        cin >> n >> m;
        maps.clear();
        vis.clear();
        maps.resize(n + 1);
        vis.resize(n + 1);
        for (int i = 1; i <= n; i++)
        {
            maps[i].resize(m + 1);
            vis[i].resize(m + 1);
        }
        for (int i = 1; i <= n; i++)
        {
            for (int j = 1; j <= m; j++)
            {
                cin >> maps[i][j];
            }
        }
        cin >> sx >> sy >> ex >> ey;
        if (sx == ex && sy == ey)
        {
            cout << 0 << endl;
            continue;
        }
        Node t;
        t.x = sx;
        t.y = sy;
        t.step = 0;
        state = maps[sx][sy];

        int ans = bfs(t);
        cout << ans << endl;
    }
    return 0;
}

 

posted @ 2018-09-07 18:15  西风show码  阅读(176)  评论(0编辑  收藏  举报