zoukankan      html  css  js  c++  java
  • UVA1601 The Morning afther Halloween

    题目大意

      w h (w, h <= 16)的网格有 n ( n <= 3) 个小写字母(代表鬼)其余的是‘#’(代表障碍格) 或 ‘ ’(代表空格。 要求把他们移动到对应的大写字母里。每步可以有多个鬼同时移动(均为上下左右4个移动方向之一), 但每步移动两个鬼不能占用同一个位置, 也不能在一步之内交换位置。输入保证空格联通,障碍联通,且在2 2子网格中至少有一个障碍格,并且最外面一层是障碍格。输入保证有解。

    基本原理

      Bfs模拟三个小鬼到处乱走的状态即可。

    优化

    1. 我们可以将带障碍的网格图更改为一张由节点和边组成的图,避免了搜索时对障碍的判断。
    2. 对于状态的判重,不要用stl的set$Olog n$解决,我们要想办法在$O(1)$的时间内判重。建图时图的节点的下标要离散化,不是其在网格图中的位置row * TotCol + col,而是新建出这个节点的序号。这样,由于位置最多有$(2^4)^2=2^8$,所以我们可以如此状态压缩:将第一个小人所在节点的编号|(第二个小人所在节点的编号<<8)|(第三个小人所在节点的编号<<16)。这样我们就可以用数组来判重了。
    3. 循环总是比递归快。进行状态转移时,不要递归每一个小人的位置。用循环枚举。对于人数<3的情况,将不用的人放到一个孤立点中即可。
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #include <iostream>
    #include <bitset>
    #include <cstdarg>
    using namespace std;
    
    const int MAX_ROW = 20, MAX_COL = 16, MAX_ROLE = 3, MAX_EDGE = MAX_ROW * MAX_COL * 4, MAX_STATE = 20000000;
    bool IsWall[MAX_ROW][MAX_COL];
    int TotRole, TotRow, TotCol;
    int Ans;
    int Dist1[MAX_STATE], Dist2[MAX_STATE];
    
    struct Node;
    struct Edge;
    
    struct Node
    {
        Edge *Head;
    }_nodes[MAX_ROW * MAX_COL];
    int _vCount;
    
    Node *_cord[MAX_ROW][MAX_COL];
    Node *NewNode(int row, int col)
    {
        return _cord[row][col] = _nodes + _vCount++;
    }
    
    struct Edge
    {
        Node *To;
        Edge *Next;
    }_edges[MAX_EDGE];
    int _eCount;
    
    void AddEdge(Node *from, Node *to)
    {
        Edge *e = _edges + ++_eCount;
        e->To = to;
        e->Next = from->Head;
        from->Head = e;
    }
    
    struct State
    {
        Node *Pos[MAX_ROLE];
        int Dist;
    
        void Clear()
        {
            memset(Pos, NULL, sizeof(Pos));
            Dist = 0;
        }
    
        State() { Clear(); }
    
        bool CanMove(Node **tos)
        {
            for (int i = 0; i < MAX_ROLE; i++)
                for (int j = i + 1; j < MAX_ROLE; j++)
                {
                    if (tos[i] == Pos[j] && tos[j] == Pos[i])
                        return false;
                    if (tos[i] == tos[j])
                        return false;
                }
            return true;
        }
    
        State GetMove(Node **tos)
        {
            State ans;
            for (int i = 0; i < MAX_ROLE; i++)
                ans.Pos[i] = tos[i];
            return ans;
        }
    }Start, Target;
    queue<State> q1, q2;
    
    void ClearAll()
    {
        memset(Dist1, -1, sizeof(Dist1));
        memset(Dist2, -1, sizeof(Dist2));
        while (!q1.empty())
            q1.pop();
        while (!q2.empty())
            q2.pop();
        Start.Clear();
        Target.Clear();
        memset(_nodes, 0, sizeof(_nodes));
        memset(_edges, 0, sizeof(_edges));
        memset(IsWall, 0, sizeof(IsWall));
        _eCount = 0;
        Ans = 0;
        _vCount = 3;
        Start.Pos[0] = _nodes, Start.Pos[1] = _nodes + 1, Start.Pos[2] = _nodes + 2;
        Target.Pos[0] = _nodes, Target.Pos[1] = _nodes + 1, Target.Pos[2] = _nodes + 2;
        memset(_cord, NULL, sizeof(_cord));
    }
    
    void BuildGraph()
    {
        for (int row = 0; row < TotRow; row++)
            for (int col = 0; col < TotCol; col++)
                if (!IsWall[row][col] && !_cord[row][col])
                    NewNode(row, col);
        for (int i = TotRole; i < MAX_ROLE; i++)
        {
            AddEdge(Start.Pos[i], Start.Pos[i]);
            AddEdge(Target.Pos[i], Target.Pos[i]);
        }
        const int Dir[4][2] = { { 1, 0 },{ 0, 1 },{ -1, 0 },{ 0, -1 } };
        for (int row = 0; row < TotRow; row++)
            for (int col = 0; col < TotCol; col++)
            {
                if (IsWall[row][col])
                    continue;
                AddEdge(_cord[row][col], _cord[row][col]);
                for (int i = 0; i < 4; i++)
                {
                    int row1 = row + Dir[i][0], col1 = col + Dir[i][1];
                    if (row1 < 0 || row1 >= TotRow || col1 < 0 || col1 >= TotCol)
                        continue;
                    if (IsWall[row1][col1])
                        continue;
                    AddEdge(_cord[row][col], _cord[row1][col1]);
                }
            }
    }
    
    int State_int(State& S)
    {
        int state = S.Pos[0] - _nodes | (S.Pos[1] - _nodes << 8) | (S.Pos[2] - _nodes << 16);
        return state;
    }
    
    void DoNext(State& cur,
        int *distIn, int *distOut,
        queue<State>& qIn)
    {
        Node *tos[MAX_ROLE];
        for (Edge *e0 = cur.Pos[0]->Head; e0; e0 = e0->Next)
            for (Edge *e1 = cur.Pos[1]->Head; e1; e1 = e1->Next)
                for (Edge *e2 = cur.Pos[2]->Head; e2; e2 = e2->Next)
                {
                    tos[0] = e0->To, tos[1] = e1->To, tos[2] = e2->To;
                    if (!cur.CanMove(tos))
                        continue;
                    State next = cur.GetMove(tos);
                    next.Dist = cur.Dist + 1;
                    int nextS = State_int(next);
                    if (distIn[nextS] >= 0)
                        continue;
                    distIn[nextS] = next.Dist;
                    if (distOut[nextS] >= 0)
                    {
                        Ans = next.Dist + distOut[nextS];
                        return;
                    }
                    qIn.push(next);
                }
    }
    
    int Bfs()
    {
        Start.Dist = Target.Dist = 0;
        Dist1[State_int(Start)] = Dist2[State_int(Target)] = 0;
        q1.push(Start);
        q2.push(Target);
        while (true)
        {
            int curDist = q1.front().Dist;
            while (q1.front().Dist == curDist)
            {
                State cur = q1.front();
                q1.pop();
                DoNext(cur, Dist1, Dist2, q1);
                if (Ans)
                    return Ans;
            }
            while (q2.front().Dist == curDist)
            {
                State cur = q2.front();
                q2.pop();
                DoNext(cur, Dist2, Dist1, q2);
                if (Ans)
                    return Ans;
            }
        }
        return Ans;
    }
    
    int main()
    {
        char s[MAX_COL + 5];
        while (scanf("%d%d%d
    ", &TotCol, &TotRow, &TotRole) && (TotRow || TotCol || TotRole))
        {
            ClearAll();
            for (int row = 0; row < TotRow; row++)
            {
                memset(s, 0, sizeof(s));
                fgets(s, sizeof(s), stdin);
                for (int col = 0; col < TotCol; col++)
                {
                    char ch = s[col];
                    if (ch == '#')
                        IsWall[row][col] = true;
                    else if ('a' <= ch && ch <= 'c')
                        Start.Pos[ch - 'a'] = NewNode(row, col);
                    else if ('A' <= ch && ch <= 'C')
                        Target.Pos[ch - 'A'] = NewNode(row, col);
                }
            }
            BuildGraph();
            printf("%d
    ", Bfs());
        }
        return 0;
    }
    

      

  • 相关阅读:
    在sql server中怎样获得正在执行的Sql查询
    在windows中使用VMWare安装Mac OS 10.7
    Scrspy 命令
    Windows Service 小品
    线程同步(一)
    线程基础必知必会(二)
    线程基础必知必会(一)
    准备工作与简介
    Python 正则表达式急速入门
    SQL Server 每日一题--每月销售额
  • 原文地址:https://www.cnblogs.com/headboy2002/p/9734209.html
Copyright © 2011-2022 走看看