Submission #674450

#TimeUsernameProblemLanguageResultExecution timeMemory
674450flashhhPortals (BOI14_portals)C++17
100 / 100
293 ms26384 KiB
#include <bits/stdc++.h>
#define ll long long
#define pii pair<int,int>
#define fi first
#define se second
#define pb emplace_back
#define eb emplace

using namespace std;

struct spInfo{
    int distance, row, column;

    spInfo() {}
    spInfo(int _distance, int _row, int _column) {
        distance = _distance; row = _row; column = _column;
    }
};
        
bool operator <(const spInfo &x, const spInfo &y) {
    return (x.distance > y.distance);
}

int xCoordinate[4] = {-1,0,0,1};
int yCoordinate[4] = {0,-1,1,0};

int numRow,numColumn;
pair<int,int> cakeCoordinate,mainCoordinate;
vector<vector<char> > labyrinth;
vector<vector<int> > distances;

void fastIO() {
    ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
}

void Read() {
    cin >> numRow >> numColumn;

    labyrinth.resize(numRow);
    for (int row = 0; row < numRow; ++row) labyrinth[row].resize(numColumn);

    for (int row = 0; row < numRow; ++row)
        for (int column = 0; column < numColumn; ++column) {
            cin >> labyrinth[row][column];

            if (labyrinth[row][column] == 'S') mainCoordinate = {row, column};
            if (labyrinth[row][column] == 'C') cakeCoordinate = {row, column};
        }    
}

void calculate() {
    vector<vector<int> > nearestSide;

    auto buildNearestSide = [&] () -> void {
        nearestSide.resize(numRow);
        for (int row = 0; row < numRow; ++row) nearestSide[row].resize(numColumn);

        for (int row = 0; row < numRow; ++row)
            for (int column = 0; column < numColumn; ++column) {
                if (labyrinth[row][column] == '#') {
                    nearestSide[row][column] = -1;
                    continue;
                }

                nearestSide[row][column] = (int)1e9;

                for (int direction = 0; direction < 4; ++direction) {
                    int adjRow = row + xCoordinate[direction]; int adjColumn = column + yCoordinate[direction];
                    if (adjRow < 0 || adjRow >= numRow || adjColumn < 0 || adjColumn >= numColumn || labyrinth[adjRow][adjColumn] == '#') {
                        nearestSide[row][column] = 0;
                        break;
                    }
                }
            }
        
        queue<pair<int,int> > myQueue;
        for (int row = 0; row < numRow; ++row)
            for (int column = 0; column < numColumn; ++column)
                if (nearestSide[row][column] == 0) myQueue.emplace(row, column);
        
        while (!myQueue.empty()) {
            auto [row, column] = myQueue.front(); myQueue.pop();
            
            for (int direction = 0; direction < 4; ++direction) {
                int adjRow = row + xCoordinate[direction]; int adjColumn = column + yCoordinate[direction];
                if (adjRow < 0 || adjRow >= numRow || adjColumn < 0 || adjColumn >= numColumn) continue;

                if (nearestSide[adjRow][adjColumn] > nearestSide[row][column] + 1) {
                    nearestSide[adjRow][adjColumn] = nearestSide[row][column] + 1;
                    myQueue.emplace(adjRow, adjColumn);
                }
            }
        }
    };

    vector<vector<int> > leftMostWall, rightMostWall, topMostWall, bottomMostWall;

    auto buildNearestWall = [&] () -> void {
        leftMostWall.resize(numRow); rightMostWall.resize(numRow);
        for (int row = 0; row < numRow; ++row) {
            leftMostWall[row].resize(numColumn);
            rightMostWall[row].resize(numColumn);
        }

        for (int row = 0; row < numRow; ++row) {
            int lastColumn = -1;
            for (int column = 0; column < numColumn; ++column) 
                if (labyrinth[row][column] == '#') lastColumn = column;
            else leftMostWall[row][column] = column - lastColumn;
            
            lastColumn = numColumn;
            for (int column = numColumn - 1; column >= 0; --column)
                if (labyrinth[row][column] == '#') lastColumn = column;
            else rightMostWall[row][column] = lastColumn - column;
        }

        topMostWall.resize(numRow); bottomMostWall.resize(numRow);
        for (int row = 0; row < numRow; ++row) {
            topMostWall[row].resize(numColumn);
            bottomMostWall[row].resize(numColumn);
        }

        for (int column = 0; column < numColumn; ++column) {
            int lastRow = -1;
            for (int row = 0; row < numRow; ++row)
                if (labyrinth[row][column] == '#') lastRow = row;
            else topMostWall[row][column] = row - lastRow;

            lastRow = numRow;
            for (int row = numRow - 1; row >= 0; --row)
                if (labyrinth[row][column] == '#') lastRow = row;
            else bottomMostWall[row][column] = lastRow - row;
        }
    };

    buildNearestSide();
    buildNearestWall();

    auto buildDistance = [&] () -> void {
        priority_queue<spInfo> prioQueue;

        distances.resize(numRow);
        for (int row = 0; row < numRow; ++row) distances[row].resize(numColumn, (int)1e9);

        distances[mainCoordinate.first][mainCoordinate.second] = 0;
        prioQueue.emplace(0, mainCoordinate.first, mainCoordinate.second);

        auto updatePrioQueue = [&] (int row, int column, int val) -> void{
            if (distances[row][column] > val) {
                distances[row][column] = val;
                prioQueue.emplace(distances[row][column], row, column);
            }
        };

        while (!prioQueue.empty()) {
            auto [distance, row, column] = prioQueue.top(); prioQueue.pop();
            if (distances[row][column] != distance) continue;

            for (int direction = 0; direction < 4; ++direction) {
                int adjRow = row + xCoordinate[direction]; int adjColumn = column + yCoordinate[direction];
                if (adjRow < 0 || adjRow >= numRow || adjColumn < 0 || adjColumn >= numColumn || labyrinth[adjRow][adjColumn] == '#') continue;

                updatePrioQueue(adjRow, adjColumn, distance + 1);
            }

            int xTeleport, yTeleport;

            xTeleport = row; yTeleport = column - leftMostWall[row][column] + 1;
            updatePrioQueue(xTeleport, yTeleport, distance + nearestSide[row][column] + 1);

            xTeleport = row; yTeleport = column + rightMostWall[row][column] - 1;
            updatePrioQueue(xTeleport, yTeleport, distance + nearestSide[row][column] + 1);

            xTeleport = row - topMostWall[row][column] + 1; yTeleport = column;
            updatePrioQueue(xTeleport, yTeleport, distance + nearestSide[row][column] + 1);

            xTeleport = row + bottomMostWall[row][column] - 1; yTeleport = column;
            updatePrioQueue(xTeleport, yTeleport, distance + nearestSide[row][column] + 1);
        }
    };

    buildDistance();
}

void printAnswer() {
    cout << distances[cakeCoordinate.first][cakeCoordinate.second] <<'\n';
}

int main() {
    fastIO();
    Read();

    calculate();
    printAnswer();

    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...