Google CodeJam习题:Always Turn Left

题目见:http://code.google.com/codejam/contest/32003/dashboard#s=p1

思路:

根据迷宫的行走路径倒推迷宫的结构。首先确定保存迷宫的数据结构。用普通的数组是不合适的,因为不知道迷宫的大小,也不知道迷宫入口的坐标。好在题目已经给定入口处在北方,所以迷宫只可能向三个方向延展。南北方向只要能够实现向容器后插入元素即可,东西方向需要能够方便的在容器前后都插入。同时还需要方便的按索引访问。这样比较合适的容器就只有std::deque了。每移动到一个新的坐标,就按照移动方向标记前一个坐标的出口和当前坐标的入口。最后再输出整个迷宫的信息。

题解:

#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <map>
#include <deque>
#include <unordered_map>

using namespace std;

class Maze
{
    enum
    {
        NORTH = (1<<0),
        SOUTH = (1<<1),
        WEST = (1<<2),
        EAST = (1<<3)
    };
    
    const string SPOT_STATUS = "0123456789abcdef";
    
    const unordered_map<int, int> TurnRight {{
            {NORTH, EAST},
            {SOUTH, WEST},
            {EAST, SOUTH},
            {WEST, NORTH}
        }
    };
    
    const unordered_map<int, int> TurnLeft {{
            {NORTH, WEST},
            {SOUTH, EAST},
            {EAST, NORTH},
            {WEST, SOUTH}
        }
    };
    
    const unordered_map<int, int> FlipMove {{
            {NORTH, SOUTH},
            {SOUTH, NORTH},
            {EAST, WEST},
            {WEST, EAST}
        }
    };
    
    const unordered_map<int, pair<int, int>> MoveForward {{
            {NORTH, {-1, 0}},
            {SOUTH, {1, 0}},
            {WEST, {0, -1}},
            {EAST, {0, 1}}
        }
    };
    
    int CurrentDirection;
    
    int MaxR, MaxC;
    int CurR, CurC;
    
    deque<deque<int>> Grid;
    
    void MoveAndExtend()
    {
        if (CurR < 0)
        {
            // this should not happen
            // since we always enter the maze at north side
            // neglect this section
        }
        else if (CurR >= MaxR)
        {
            ++MaxR;
            Grid.emplace_back (deque<int> (MaxC, 0));
        }
        else if (CurC < 0)
        {
            ++CurC;
            ++MaxC;
            for (auto& r : Grid)
                r.push_front (0);
            CurC = 0;
        }
        else if (CurC >= MaxC)
        {
            ++MaxC;
            for (auto& r : Grid)
                r.push_back (0);
        }
        
        Grid[CurR][CurC] |= FlipMove.at (CurrentDirection);
    }
    
    void Visit (const string& v)
    {
        for (auto& ch : v)
        {
            switch (ch)
            {
            case 'W':
                Grid[CurR][CurC] |=  CurrentDirection;
                CurR += MoveForward.at (CurrentDirection).first;
                CurC += MoveForward.at (CurrentDirection).second;
                MoveAndExtend();
                break;
            case 'R':
                CurrentDirection = TurnRight.at (CurrentDirection);
                break;
            case 'L':
                CurrentDirection = TurnLeft.at (CurrentDirection);
                break;
            }
        }
    }
    
public:
    void BidirectionTraverse (const string& forward, const string& backward)
    {
        MaxR = MaxC = 1;
        CurC = 0;
        CurR = 0;  // we enter from outside of the maze
        
        Grid.push_back (deque<int> (1, 0));
        
        CurrentDirection = SOUTH;
        
        // Give the entrance "CAN WALK NORTH" attribute
        Grid[0][0] |= NORTH;
        
        // we neglect the first move-in and last move-out instruction
        Visit (forward.substr (1, forward.size()-2));
        
        Grid[CurR][CurC] |= CurrentDirection;
        
        CurrentDirection = FlipMove.at (CurrentDirection);
        Visit (backward.substr (1, backward.size()-2));
    }
    
    void Print()
    {
        for (auto& c1 : Grid)
        {
            for (auto& c2 : c1)
                cout<<SPOT_STATUS[c2];
            cout<<endl;
        }
    }
};

int main (int argc, char* argv[])
{
    int num_sample;
    cin>>num_sample;
    
    vector<Maze> m;
    for (int i = 0; i < num_sample; ++i)
    {
        string enter, exit;
        cin>>enter>>exit;
        m.push_back (Maze());
        m.back().BidirectionTraverse (enter, exit);
    }
    
    for (int i = 0; i < num_sample; ++i)
    {
        cout<<"Case #"<<i+1<<":"<<endl;
        m[i].Print();
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值