Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

51-tgyuuAn #179

Merged
merged 2 commits into from
May 3, 2024
Merged

51-tgyuuAn #179

merged 2 commits into from
May 3, 2024

Conversation

tgyuuAn
Copy link
Member

@tgyuuAn tgyuuAn commented Apr 8, 2024

🔗 문제 링크

과외맨

✔️ 소요된 시간

40분

image

원큐에 뽝!!!

✨ 수도 코드

사실 로직 자체는 되게 간단하다.

아래와 같이 타일이 주어지는데,

하나의 타일2개의 숫자로 이루어져 있다.

image







이 타일은 (0,0) 에서 시작해서 마지막 줄의 마지막 칸 까지 이동 시켜야 하는데,

이 과정에서 서로 맞닿아 있는 타일은 같은 수로 붙어있을 경우에만 이동할 수 있다.

image







이 때, 마지막 칸으로 이동할 때 나올 수 있는 최소 횟수를 구하고,

해당 경우에서 움직인 타일 경로를 출력 해야한다.







N의 최대 값500으로 매우 작기 때문에,

일반적인 BFS로 해결할 수 있다.

마지막에 움직인 타일의 경로는 #177 홍주님의 10번 PR에서 구했듯이,

부모 타일을 저장한 뒤 마지막에 역추적 하는 방식으로 손쉽게 구할 수 있따.







근데... BFS로 타일을 움직일 때 구현이 너무 너무 귀찮다.

홀수번째 줄 일 때 이동할 수 있는 값은 dy-1이나 1일 때, dx-1이나 0으로 움직일 수 있다.

근데 dy가 0일때는 dx는 -1과 +1이 되어야 한다.

image

(그림에 좌측 하단에 N-1으로 되어있는데 N이다..)







짝수번째 줄 일 때 이동할 수 있는 값은 dy-1이나 1일 때, dx0이나 +1으로 움직일 수 있다.

근데 dy0일 때는 dx는 역시나 -1+1이 되어야 한다.

image







이거 구현이 은근 귀찮다...

그리고.. 마지막으로 아래 구문을 해결해주기 위해서,

image

BFS매 타일을 움직일 때 마다 타일 수가 큰 수를 계속 계속 기록해준다.

만약 중간에 종착지에 도착하지 못했을 경우, 해당 타일 번호가 가장 큰 수로 가는 횟수와 경로를 역추적 해주면 끝!!

📚 새롭게 알게된 내용

@tgyuuAn tgyuuAn added tgyuuAn 한 줄로는 소개할 수 없는 남자. 리뷰 기다리는 중 🔥 labels Apr 8, 2024
@tgyuuAn tgyuuAn self-assigned this Apr 8, 2024
@9kyo-hwang
Copy link

1시간 박았으나 테케 3번에서 컷...
시험 공부 좀 하다가 다시 트라이 해봐야겠다... ㅜ

@tgyuuAn
Copy link
Member Author

tgyuuAn commented Apr 20, 2024

1시간 박았으나 테케 3번에서 컷...

시험 공부 좀 하다가 다시 트라이 해봐야겠다... ㅜ

당신 시험기간 아냐....??????

@9kyo-hwang
Copy link

1시간 박았으나 테케 3번에서 컷...
시험 공부 좀 하다가 다시 트라이 해봐야겠다... ㅜ

당신 시험기간 아냐....??????

공부하기 뒤지게 싫어서 쉴 겸... 트라이 했는데 문제 왤케 거지같음? ㅋㅋㅋㅋ

Copy link

@9kyo-hwang 9kyo-hwang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

휴 토탈 1시간 반...
맞게 풀고 있었는데 북동, 동, 남동 방향으로 가는 거랑 남서, 서, 북서 방향으로 갈 때 검사 칸을 다르게 해줘야 하는 걸 놓쳤었네.
어우 조건 까다로워.
시험 끝나고 요걸로 PR 써야징

from collections import deque
input = open(0).readline


def out_of_bound(N: int, tile: list, x: int, y: int) -> bool:
    return not(0 <= x < N and 0 <= y < N * 2 and 1 <= tile[x][y] <= 6)


def pos_to_num(N: int, x: int, y: int) -> int:
    y += 1 if x & 1 else 2
    y >>= 1
    return y + x * N - x // 2
    

def bfs(N: int, tile: list, parents: list) -> tuple:
    q = deque([(0, 0, 1)])
    visited = [False] * (pos_to_num(N, N, N * 2) + 1)
    visited[pos_to_num(N, 0, 0)] = True
    
    max_t, max_d = 0, 0
    while q:
        x, y, d = q.popleft()
        t = pos_to_num(N, x, y)
        
        if t > max_t:
            max_t = t
            max_d = d
            
        
        for dx, dy in [(-1, 1), (0, 2), (1, 1)]:  # NE, E, SE
            nx, ny = x + dx, y + dy
            nt = pos_to_num(N, nx, ny)
            if out_of_bound(N, tile, nx, ny) or visited[nt] or tile[x][y + 1] != tile[nx][ny]:
                continue
            
            visited[nt] = True
            parents[nt] = t
            q.append((nx, ny, d + 1))
            
            
        for dx, dy in [(1, -1), (0, -2), (-1, -1)]:  # SW, W, NW
            nx, ny = x + dx, y + dy
            nt = pos_to_num(N, nx, ny)
            if out_of_bound(N, tile, nx, ny) or visited[nt] or tile[x][y] != tile[nx][ny + 1]:
                continue
            
            visited[nt] = True
            parents[nt] = t
            q.append((nx, ny, d + 1))
    
    
    return (max_t, max_d)


def dfs(parents: list, tile: int):
    if parents[tile] == tile:
        return
    
    dfs(parents, parents[tile])
    print(tile, end=' ')


def main():
    N = int(input())
    tile = [[0] * (N * 2) for _ in range(N)]
    
    for i in range(N):
        if i & 1:
            for j in range(1, N * 2 - 1, 2):
                tile[i][j], tile[i][j + 1] = map(int, input().split())
        else:
            for j in range(0, N * 2, 2):
                tile[i][j], tile[i][j + 1] = map(int, input().split())
                
    
    parents = [0] * (pos_to_num(N, N, N * 2) + 1)
    max_t, max_d = bfs(N, tile, parents)
    
    print(max_d)
    dfs(parents, max_t)


if __name__ == "__main__":
    main()
image

아싸 4등


여기는 먼저 C++로 푼 거

#include <iostream>
#include <vector>
#include <queue>
#include <tuple>
#include <functional>

using namespace std;

int main()
{
    cin.tie(nullptr)->sync_with_stdio(false);
    
    int N; cin >> N;
    vector<vector<int>> Tile(N, vector(N * 2, 0));
    for(int i = 0; i < N; ++i)
    {
        if(i % 2 == 1)
        {
            for(int j = 1; j < N * 2 - 1; j += 2)
            {
                cin >> Tile[i][j] >> Tile[i][j + 1];
            }
        }
        else
        {
            for(int j = 0; j < N * 2; j += 2)
            {
                cin >> Tile[i][j] >> Tile[i][j + 1];
            }
        }
    }
    
    auto OutOfBound = [&](int X, int Y)
    {
        return X < 0 || X >= N || Y < 0 || Y >= 2 * N || Tile[X][Y] == 0;
    };
    
    auto Pos2Num = [&](int X, int Y)
    {
        if(X % 2 == 1)
        {
            Y += 1;
        }
        else
        {
            Y += 2;
        }
        Y /= 2;

        return Y + X * N - X / 2;
    };
    
    deque<tuple<int, int, int>> Q;
    vector<bool> Visited(Pos2Num(N, N * 2) + 1, false);
    vector<int> Parents(Pos2Num(N, N * 2) + 1, 0);
    
    Q.emplace_back(0, 0, 1);
    Visited[Pos2Num(0, 0)] = true;
    
    const vector<pair<int, int>> ToEast = {{-1, 1}, {0, 2}, {1, 1}};
    const vector<pair<int, int>> ToWest = {{1, -1}, {0, -2}, {-1, -1}};
    
    int MaxTile = 0, MaxD = 0;
    while(!Q.empty())
    {
        const auto [X, Y, D] = Q.front();
        Q.pop_front();
        
        if(Pos2Num(X, Y) > MaxTile)
        {
            MaxTile = Pos2Num(X, Y);
            MaxD = D;
        }
        
        for(const auto& [Dx, Dy] : ToEast)
        {
            int Nx = X + Dx, Ny = Y + Dy;
            if(OutOfBound(Nx, Ny) || Visited[Pos2Num(Nx, Ny)] || Tile[X][Y + 1] != Tile[Nx][Ny])
            {
                continue;
            }
            
            Visited[Pos2Num(Nx, Ny)] = true;
            Parents[Pos2Num(Nx, Ny)] = Pos2Num(X, Y);
            Q.emplace_back(Nx, Ny, D + 1);
        }
        
        for(const auto& [Dx, Dy] : ToWest)
        {
            int Nx = X + Dx, Ny = Y + Dy;
            if(OutOfBound(Nx, Ny) || Visited[Pos2Num(Nx, Ny)] || Tile[X][Y] != Tile[Nx][Ny + 1])
            {
                continue;
            }
            
            Visited[Pos2Num(Nx, Ny)] = true;
            Parents[Pos2Num(Nx, Ny)] = Pos2Num(X, Y);
            Q.emplace_back(Nx, Ny, D + 1);
        }
    }
    
    function<void(int)> DFS = [&](int Tile)
    {
        if(Parents[Tile] == Tile)
        {
            return;
        }
        
        DFS(Parents[Tile]);
        cout << Tile << " ";
    };
    
    
    cout << MaxD << "\n";
    DFS(MaxTile);
    
    return 0;
}

@tgyuuAn tgyuuAn merged commit 7c8ec30 into main May 3, 2024
@tgyuuAn tgyuuAn deleted the 51-tgyuuAn branch May 3, 2024 15:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
tgyuuAn 한 줄로는 소개할 수 없는 남자. 리뷰 완료 ✔️
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants