Tävlingsprogrammering/Uppgifter/Skridskor

Från Wikibooks

Se skridskoplanen som en graf där du vill hitta kortaste vägen ut. Alltså är det ett SSSP problem där vi kan använda en BFS sökning för att hitta svaret i O(V+E).

Notera att lösningen nedan är O(E log V) snarare än O(E), eftersom operationerna på dist (som är en map) tar tid O(log V).

Lösning av Andreas Wallström:

#include <iostream>
#include <vector>
#include <queue>
#include <utility>
#include <string.h>
#include <tuple>
#include <map>
 
#define DIR_U 0
#define DIR_R 1
#define DIR_D 2
#define DIR_L 3
 
using namespace std;
 
int R, C;
vector<vector<char>> theMap;
 
int main() {
    ios_base::sync_with_stdio(false); // Speedar upp cin till scanf() nivåer ;)
 
    char entity;
    cin >> R >> C;
    theMap.assign(R, vector<char>(C));
 
    for(int y = 0; y < R; y++) {
        for(int x = 0; x < C; x++) {
            cin >> entity;
            theMap[y][x] = entity;
        }
    }
 
    map<pair<int, int>, long long int> dist;
    dist[make_pair(0, 0)] = 0;
    queue<tuple<int, int, int>> q;
    q.push(make_tuple(0, 0, DIR_R)); //(y, x, dir)
    

    // DFS börjar här
    while(!q.empty()) {
        tuple<int, int, int> u = q.front();
        q.pop();
        int oldY = get<0>(u);
        int oldX = get<1>(u);
        int dir  = get<2>(u);
        
        // Din nya riktning kommer alltid att vara +90 och -90 grader från den du har nu
        int newDir1 = ((dir + 1) % 4);
        int newDir2 = ((dir == 0) ? 3 : dir - 1);
 
        int newX = -1, newY = -1;
        
        // Gå åt de håll hon åker, gå tills du stöter på ett hinder (#). Det blir din nya position
        switch(dir) {
        case DIR_R:
            for(int x = oldX; x <= C; x++) { // Scanna hela vägen åt höger efter ett hinder (#)
                if(theMap[oldY][x] == '#') {
                    newX = x-1;
                    newY = oldY;
                    break;
                }
                else if(x == C-1) {
                    
                    // Klar, skriv ut svaret! (man kommer alltid åka ut på höger sida)
                    cout << dist[make_pair(oldY, oldX)] << endl;
                    return 0;
                }
            }
        break;
        case DIR_D:
            for(int y = oldY; y < R; y++) { // Scanna hela vägen neråt efter ett hinder (#)
                if(theMap[y][oldX] == '#') {
                    newX = oldX;
                    newY = y-1;
                    break;
                }
            }
        break;
        case DIR_L: // Scanna hela vägen åt vänster efter ett hinder (#)
            for(int x = oldX; x >= 0; x--) {
                if(theMap[oldY][x] == '#') {
                    newX = x+1;
                    newY = oldY;
                    break;
                }
            }
        break;
        case DIR_U: // Scanna hela vägen uppåt efter ett hinder (#)
            for(int y = oldY; y >= 0; y--) {
                if(theMap[y][oldX] == '#') {
                    newX = oldX;
                    newY = y+1;
                    break;
                }
            }
        break;
        }
 
        if(newX == -1 || newY == -1) {
            continue;
        }
 
        //newX == 0 && newY == 0 är ett edge case
        if(dist.find(make_pair(newY, newX)) == dist.end() || newX == 0 && newY == 0) {
            dist[make_pair(newY, newX)] = dist[make_pair(oldY, oldX)] + 1;
            q.push(make_tuple(newY, newX, newDir1));
            q.push(make_tuple(newY, newX, newDir2));
        }
    }
}