Skip to content

Conversation

@froglike6
Copy link
Collaborator

@froglike6 froglike6 commented Jun 26, 2025

πŸ”— 문제 링크

μ•„λ§žλ‹€μš°μ‚°

βœ”οΈ μ†Œμš”λœ μ‹œκ°„

1μ‹œκ°„

✨ μˆ˜λ„ μ½”λ“œ

μˆ˜λ„μ½”λ“œ(μ•½κ°„ μ–΄λ €μšΈ 것 κ°™μ•„ 주석도 λ‹¬μ•˜μ–΄μš”)

μž…λ ₯ n, m
μž…λ ₯ m μ€„μ˜ λ¬Έμžμ—΄λ‘œ μ§‘ ꡬ쑰 grid λ₯Ό μ €μž₯ν•œλ‹€

start, exit ← None  
item ← 빈 리슀트

λͺ¨λ“  μ’Œν‘œ (y, x)에 λŒ€ν•΄:
    λ§Œμ•½ grid[y][x] == "S" 라면:
        start ← (y, x)
    μ•„λ‹ˆλΌλ©΄ grid[y][x] == "E" 라면:
        exit ← (y, x)
    μ•„λ‹ˆλΌλ©΄ grid[y][x] == "X" 라면:
        item λͺ©λ‘μ— (y, x) μΆ”κ°€

node ← [start] + item + [exit]  
k ← item 의 개수  
l ← k + 2          # 전체 λ…Έλ“œ 수(S, Xλ“€, E)

dist ← l Γ— l 배열을 -1 둜 μ΄ˆκΈ°ν™”  
dirs ← {(1, 0), (-1, 0), (0, 1), (0, -1)}

각 λ…Έλ“œ (sy, sx) 와 κ·Έ 인덱슀 idx 에 λŒ€ν•΄:
    d ← m Γ— n 배열을 -1 둜 μ΄ˆκΈ°ν™”
    큐 q ← (sy, sx) λ₯Ό λ„£μ–΄ 생성
    d[sy][sx] ← 0

    while q κ°€ λΉ„μ–΄μžˆμ§€ μ•Šλ‹€λ©΄:
        (y, x) ← q μ—μ„œ κΊΌλ‚Έλ‹€
        dirs 의 λ„€ λ°©ν–₯ (dy, dx) 에 λŒ€ν•΄:
            ny ← y + dy, nx ← x + dx
            λ§Œμ•½ 0 ≀ ny < m, 0 ≀ nx < n,
                 그리고 grid[ny][nx] != '#',
                 그리고 d[ny][nx] == -1 이라면:
                d[ny][nx] ← d[y][x] + 1
                q 에 (ny, nx) μΆ”κ°€

    λͺ¨λ“  λ…Έλ“œ (ty, tx) 와 인덱슀 j 에 λŒ€ν•΄:
        dist[idx][j] ← d[ty][tx]          # idx ↔ j μ΅œλ‹¨ 거리 기둝

λ§Œμ•½ k == 0 (μ±™κΈΈ 물건이 μ—†λ‹€λ©΄):
    dist[0][1] 을 좜λ ₯ν•œλ‹€           # Sβ†’E μ΅œλ‹¨ 거리

κ·Έ μ™Έμ˜ 경우:                      # 물건을 ν•˜λ‚˜ 이상 챙겨야 ν•  λ•Œ
    INF ← 10^9
    dp ← (1 << k) Γ— (k + 1) 배열을 INF 둜 μ΄ˆκΈ°ν™”
    dp[0][0] ← 0                    # (아무것도 μ•ˆ μ±™κΉ€, S μœ„μΉ˜)

    λͺ¨λ“  λΉ„νŠΈλ§ˆμŠ€ν¬ mask (0 ~ 2^k - 1)에 λŒ€ν•΄:
        i = 0 ~ k κΉŒμ§€:
            cur ← dp[mask][i]
            λ§Œμ•½ cur == INF 라면: λ‹€μŒ i 둜
            j = 0 ~ k - 1 κΉŒμ§€:
                λ§Œμ•½ mask 에 j 번째 λΉ„νŠΈκ°€ 켜져 μžˆλ‹€λ©΄: continue
                cost ← dist[i][j + 1]        # ν˜„ μœ„μΉ˜ i β†’ μƒˆ μ•„μ΄ν…œ j
                λ§Œμ•½ cost == -1 이라면: continue
                nxt ← mask | (1 << j)
                dp[nxt][j + 1] ← min(dp[nxt][j + 1], cur + cost)

    all_mask ← (1 << k) - 1          # λͺ¨λ“  μ•„μ΄ν…œμ„ μ±™κΈ΄ μƒνƒœ
    ans ← INF
    i = 0 ~ k κΉŒμ§€:
        λ§Œμ•½ dp[all_mask][i] == INF μ΄κ±°λ‚˜ dist[i][k + 1] == -1 라면: continue
        ans ← min(ans, dp[all_mask][i] + dist[i][k + 1])   # λ§ˆμ§€λ§‰μœΌλ‘œ E κΉŒμ§€ 이동

    ans λ₯Ό 좜λ ₯ν•œλ‹€

이 λ¬Έμ œλŠ” λ‹¨μˆœν•œ BFS λ¬Έμ œμ™€ λΉ„μŠ·ν•˜μ§€λ§Œ, μ•½κ°„ λ‹€λ₯Έ λ¬Έμ œμž…λ‹ˆλ‹€. BFS둜 λͺ¨λ“  경둜의 길이λ₯Ό κ΅¬ν•˜κ³ , λΉ„νŠΈλ§ˆμŠ€ν¬ DPλ₯Ό 톡해 κ°€μž₯ 적게 μ›€μ§μ΄λŠ” 경둜λ₯Ό μ°ΎμŠ΅λ‹ˆλ‹€. λΉ„νŠΈλ§ˆμŠ€ν¬λŠ” #24 에 μ„€λͺ…λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€ γ…Žγ…Ž. 이λ₯Ό ν™œμš©ν•œ DP라고 μƒκ°ν•˜μ‹œλ©΄ λ˜κ² μŠ΅λ‹ˆλ‹€.

격자 μ•ˆμ˜ μΆœλ°œμ μ—μ„œ μ‹œμž‘ν•˜μ—¬ λͺ¨λ“  μ•„μ΄ν…œμ„ μ–»κ³ , 좜ꡬ둜 이동해야 ν•©λ‹ˆλ‹€. λ¨Όμ € μž…λ ₯μ—μ„œ 격자λ₯Ό λ°›κ³ , 탐색할 λ…Έλ“œλ₯Ό node에 μ €μž₯ν•©λ‹ˆλ‹€(S, λͺ¨λ“  E, X).
그런 λ‹€μŒ node의 λͺ¨λ“  λ…Έλ“œμ— λŒ€ν•΄ BFSλ₯Ό 돌렀 λͺ¨λ“  λ…Έλ“œ κ°„ μ΅œλ‹¨ 거리 ν–‰λ ¬ distλ₯Ό λ§Œλ“­λ‹ˆλ‹€.

이제 λΉ„νŠΈλ§ˆμŠ€ν¬ DP둜 λ„˜μ–΄κ°€κ² μŠ΅λ‹ˆλ‹€.
maskλŠ” kλΉ„νŠΈ μ§‘ν•©μœΌλ‘œ, 각 λΉ„νŠΈκ°€ 1이면 ν•΄λ‹Ή μ•„μ΄ν…œμ„ νšλ“ν–ˆλ‹€κ³  μ„€μ •ν–ˆμŠ΅λ‹ˆλ‹€. 그런 λ‹€μŒ dp[mask][i]에닀가, mask된 μƒνƒœμ—μ„œ node[i]에 λ„μ°©ν•œ μ΅œμ†Œ 거리λ₯Ό μ €μž₯ν–ˆμŠ΅λ‹ˆλ‹€. λͺ¨λ“  μ•„μ΄ν…œμ„ μˆœνšŒν•˜κ³  좜ꡬ둜 λ‚˜κ°€, 닡을 λ„μΆœν•  수 μžˆμ—ˆμŠ΅λ‹ˆλ‹€.

πŸ“š μƒˆλ‘­κ²Œ μ•Œκ²Œλœ λ‚΄μš©

λΉ„νŠΈλ§ˆμŠ€ν¬ DPλ₯Ό μ•Œκ²Œ λ˜μ—ˆμŠ΅λ‹ˆλ‹€. 이 λ¬Έμ œμ—μ„œλŠ” μ•„μ΄ν…œμ˜ μˆ˜κ°€ μž‘μ•„μ„œ λ‹€μ΅μŠ€νŠΈλΌλ₯Ό μ‚¬μš©ν•˜μ§€ μ•Šμ•˜λŠ”λ°, μƒˆλ‘œ μ•Œκ²Œ 된 λΉ„νŠΈλ§ˆμŠ€ν¬ DPλ₯Ό μ‚¬μš©ν•˜λ©΄μ„œ 비ꡐ적 더 λΉ λ₯΄κ²Œ 계산할 수 μžˆμ—ˆμŠ΅λ‹ˆλ‹€.

Copy link
Contributor

@dohyeondol1 dohyeondol1 left a comment

Choose a reason for hiding this comment

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

λΉ„νŠΈλ§ˆμŠ€ν‚Ήμ€ 아직 μ΅μˆ™ν•˜μ§€κ°€ μ•Šμ•„μ„œ κ·ΈλŸ°κ°€ 풀이λ₯Ό μ•Œμ•„λ‚΄λ„ μ½”λ“œλ₯Ό λ°”λ‘œ μ§œκΈ°κ°€ μ–΄λ ΅λ„€μš”...
κ·Έλ§ˆμ €λ„ λΉ„νŠΈλ§ˆμŠ€ν¬ dpκ°€ μ•„λ‹ˆλΌ λΉ„νŠΈλ§ˆμŠ€ν¬λ§Œ μ‚¬μš©ν•˜μ˜€μŠ΅λ‹ˆλ‹€.
μ°Ύμ•„λ³΄λ‹ˆ μ™ΈνŒμ› 순회(TSP)도 λΉ„νŠΈλ§ˆμŠ€ν¬ DPλ₯Ό μ‚¬μš©ν•œλ‹€κ³  ν•˜λ˜λ°...
BFS μ—°μŠ΅ 뿐만 μ•„λ‹ˆλΌ μ‘μš©ν•  수 μžˆλŠ” λ‚΄μš©λ„ μžˆμ–΄μ„œ λ°°μ›Œκ°ˆκ²Œ λ§Žμ€ λ¬Έμ œλ„€μš” γ…Žγ…Ž

μ €λŠ” visited[y][x][mask] μƒνƒœλ‘œ 탐색을 μˆ˜ν–‰ν–ˆμŠ΅λ‹ˆλ‹€.
λΉ„νŠΈλ§ˆμŠ€ν¬λŠ” μƒνƒœκ΄€λ¦¬ μš©λ„λ‘œλ§Œ μ‚¬μš©ν–ˆμ–΄μš₯
μ•„μ΄ν…œ κ°œμˆ˜κ°€ λ§Žμ•„μ§„λ‹€λ©΄ μ’€ λΉ„νš¨μœ¨μ μΌμˆœ μžˆκ² λ„€μš”..

#include <iostream>
#include <queue>
#include <vector>
#include <tuple>
#include <algorithm>
using namespace std;

int N, M;
vector<string> house;
vector<pair<int, int>> items;
int dx[4] = {0, 1, 0, -1};
int dy[4] = {-1, 0, 1, 0};

int bfs(int sy, int sx, int ey, int ex, const vector<pair<int, int>>& items) {
    int item_cnt = items.size();
    vector<vector<int>> item_idx(M, vector<int>(N, -1));
    for (int i = 0; i < item_cnt; ++i)
        item_idx[items[i].first][items[i].second] = i;

    vector<vector<vector<int>>> visited(M, vector<vector<int>>(N, vector<int>(1 << item_cnt, 0)));
    queue<tuple<int, int, int, int>> q;
    q.push({sy, sx, 0, 0});
    visited[sy][sx][0] = 1;

    while(!q.empty()) {
        auto [y, x, mask, dist] = q.front();
        q.pop();

        if(y == ey && x == ex && mask == (1<<item_cnt)-1)
            return dist;

        for(int dir = 0; dir < 4; ++dir) {
            int ny = y + dy[dir];
            int nx = x + dx[dir];
            if(ny < 0 || ny >= M || nx < 0 || nx >= N) continue;
            if(house[ny][nx] == '#') continue;

            int nmask = mask;
            if(item_idx[ny][nx] != -1)
                nmask |= (1 << item_idx[ny][nx]);
            if(!visited[ny][nx][nmask]) {
                visited[ny][nx][nmask] = 1;
                q.push({ny, nx, nmask, dist + 1});
            }
        }
    }
    return -1;
}

int main() {
    cin.tie(nullptr)->sync_with_stdio(false);
    
    cin >> N >> M;
    house.resize(M);
    for(int i = 0; i < M; ++i)
        cin >> house[i];

    int sy, sx, ey, ex;
    items.clear();
    for(int i = 0; i < M; ++i) {
        for(int j = 0; j < N; ++j) {
            if(house[i][j] == 'S') sy = i, sx = j;
            if(house[i][j] == 'E') ey = i, ex = j;
            if(house[i][j] == 'X') items.push_back({i, j});
        }
    }

    int answer = bfs(sy, sx, ey, ex, items);
    cout << answer << '\n';
    return 0;
}

@froglike6 froglike6 changed the base branch from 16-froglike6 to main July 2, 2025 03:40
@Fnhid
Copy link
Collaborator

Fnhid commented Jul 2, 2025

저도 λΉ„νŠΈλ§ˆμŠ€ν‚Ήμ„ 처음 μ ‘ν•΄λ³΄μ•„μ„œ μˆ˜λ„ μ½”λ“œ λ³΄λ©΄μ„œ μ§œλ³΄μ•˜μŠ΅λ‹ˆλ‹€..!

bfsλŠ” ν•˜λ˜ λŒ€λ‘œ ν–ˆκ³ ,
dp[a][b]μ—μ„œ
aλ₯Ό κ°€μž₯ μ΅œκ·Όμ— λ°©λ¬Έν•œ 물건, bλ₯Ό λ°©λ¬Έν•œ 물건의 μ§‘ν•©μœΌλ‘œ μž‘μ„±ν–ˆμ–΄μš”

#include <iostream>
#include <queue>
#include <vector>

using namespace std;
#define X first
#define Y second
#define INF 999999999

int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0, 0};

vector<vector<int> > bfs(pair<int, int> sp, int m, int n, const vector<string> &map) {
    vector<vector<int> > visited(m, vector<int>(n, -1));
    queue<pair<int, int> > q;

    q.push(sp);
    visited[sp.X][sp.Y] = 0;

    while (!q.empty()) {
        pair<int, int> cur = q.front();
        q.pop();

        for (int i = 0; i < 4; i++) {
            int nx = cur.X + dx[i];
            int ny = cur.Y + dy[i];
            if (nx < 0 || nx >= m || ny < 0 || ny >= n ||
                map[nx][ny] == '#' || visited[nx][ny] != -1)
                continue;
            visited[nx][ny] = visited[cur.X][cur.Y] + 1;
            q.push({nx, ny});
        }
    }
    return visited;
}

int main() {
    vector<pair<int, int> > x;
    pair<int, int> s, e;

    vector<pair<int, int> > p;

    int n, m;
    cin >> n >> m;

    vector<string> map;
    map.resize(m);


    for (int i = 0; i < m; i++) {
        cin >> map[i];
    }

    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            if (map[i][j] == 'S') {
                s.X = i;
                s.Y = j;
            } else if (map[i][j] == 'E') {
                e.X = i;
                e.Y = j;
            } else if (map[i][j] == 'X')
                x.push_back(pair<int, int>(i, j));
        }
    }

    p.push_back(s);
    for (const auto &i: x)
        p.push_back(i);
    p.push_back(e);
    int p_size = p.size();
    vector<vector<int> > dist_matrix(p_size, vector<int>(p_size));

    //bfs
    for (int i = 0; i < p_size; i++) {
        vector<vector<int> > dist = bfs(p[i], m, n, map);
        for (int j = 0; j < p_size; j++) {
            dist_matrix[i][j] = dist[p[j].X][p[j].Y];
        }
    }

    int x_size = x.size();

    if (x_size == 0) {
        cout << dist_matrix[0][1] << endl;
        return 0;
    }
    // dp
    vector<vector<int> > dp(x_size, vector<int>(1 << x_size, INF));

    for (int i = 0; i < x_size; i++) {
        dp[i][1 << i] = dist_matrix[0][i + 1];
    }

    for (int mask = 1; mask < (1 << x_size); mask++) {
        for (int i = 0; i < x_size; i++) {
            if (mask & (1 << i)) {
                for (int j = 0; j < x_size; j++) {
                    if (!(mask & (1 << j))) {
                        int cost = dist_matrix[i + 1][j + 1];
                        int next_mask = mask | (1 << j);
                        dp[j][next_mask] = min(dp[j][next_mask], dp[i][mask] + cost);
                    }
                }
            }
        }
    }
    int min_total_dist = INF;
    int all_mask = (1 << x_size) - 1;

    for (int i = 0; i < x_size; i++) {
        int cost_to_end = dist_matrix[i + 1][x_size + 1];
        min_total_dist = min(min_total_dist, cost_to_end + dp[i][all_mask]);
    }
    cout << min_total_dist << endl;
    return 0;
}

Copy link
Member

@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.

λΉ„νŠΈ λ§ˆμŠ€ν‚ΉμœΌλ‘œ ν˜„μž¬ μ±™κΈ΄ 물건듀을 ν‘œν˜„ν•˜λ©΄, visited λ°©λ¬Έ 처리λ₯Ό μ‰½κ²Œ ν•΄λ‚Ό 수 있죠. μ•½κ°„ μ–΄λ €μš΄ κ·Έλž˜ν”„ λ¬Έμ œλŠ” λΉ„νŠΈ λ§ˆμŠ€ν‚Ήμ„ μ„žλŠ” μͺ½μœΌλ‘œ κΎΈμ€€νžˆ λ‚˜μ˜€λŠ” 것 κ°™μ•„μš” :)

그런데 μ£Όμ–΄μ§€λŠ” μž…λ ₯을 보면 μ§‘ ν¬κΈ°λ‚˜ μ•„μ΄ν…œ 개수의 μ΅œλŒ€κ°’μ΄ μž‘κΈ° λ•Œλ¬Έμ— 쑰금 λΉ„νš¨μœ¨μ μΈ 풀이도 될 것 κ°™λ”λΌκ΅¬μš”. μ €λŠ” μ•„λž˜μ™€ 같이 ν’€μ–΄λ΄€μŠ΅λ‹ˆλ‹€.

  1. μ‹œμž‘ 지점 S와 도착 지점 EλŠ” κ³ μ •
  2. S, E 사이에 λ°©λ¬Έν•΄μ•Ό ν•  μ•„μ΄ν…œ μˆœμ„œλ₯Ό "μˆœμ—΄"을 μ΄μš©ν•΄ λͺ¨λ“  경우의 수λ₯Ό 확인
  3. S -> $X_1$에 λŒ€ν•΄ BFS / $X_1$ -> $X_2$에 λŒ€ν•΄ BFS / ... / $X_k$ -> E에 λŒ€ν•΄ BFSλ₯Ό μˆ˜ν–‰, 각각의 BFSλ‘œλΆ€ν„° λ°˜ν™˜λœ μ΅œλ‹¨ 경둜의 합을 계산
  4. 이 μ΅œλ‹¨ 경둜 ν•© 쀑 κ°€μž₯ μž‘μ€ 값을 좜λ ₯
μ†ŒμŠ€ μ½”λ“œ

#include <bits/stdc++.h>

using namespace std;
using Vector2 = pair<int32_t, int32_t>;

enum : uint8_t {
    START = 'S',
    END = 'E',
    ITEM = 'X',
    EMPTY = '.',
    WALL = '#',
};

const vector<Vector2> OFFSET {
    {-1, 0},
    {0, 1},
    {1, 0},
    {0, -1}
};

int32_t N, M;
vector<vector<int32_t>> gVisited;
Vector2 s, e;
vector<Vector2> items;

inline bool isOutOfBound(int i, int j) {
    return i < 0 || i >= N || j < 0 || j >= M;
}

int32_t BFS(Vector2 src, Vector2 dst) {
    queue<Vector2> q;
    q.emplace(src);
    
    vector<vector<int32_t>> visited = gVisited;
    visited[src.first][src.second] = 0;
    
    int32_t move = 0;
    while(!q.empty()) {
        const auto cur = q.front();
        q.pop();
        
        if(cur == dst) {
            move = visited[dst.first][dst.second];
            break;
        }
        
        const auto& [i, j] = cur;
        for(const auto& [di, dj] : OFFSET) {
            int32_t ni = i + di, nj = j + dj;
            if(isOutOfBound(ni, nj) || visited[ni][nj] > -1) {
                continue;
            }
            
            visited[ni][nj] = visited[i][j] + 1;
            q.emplace(ni, nj);
        }
    }
    
    return move;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    cin >> M >> N;
    gVisited.assign(N, vector<int32_t>(M, -1));

    for(int32_t i = 0; i < N; ++i) {
        for(int32_t j = 0; j < M; ++j) {
            uint8_t val; cin >> val;
            if(val == WALL) {
                gVisited[i][j] = 0;
                continue;
            }
            
            if(val == START) {
                s = {i, j};
            } else if(val == END) {
                e = {i, j};
            } else if(val == ITEM) {
                items.emplace_back(i, j);
            }
        }
    }
    
    if(items.empty()) {
        cout << BFS(s, e);
        return 0;
    }
    
    sort(items.begin(), items.end());
    
    int32_t ans = 1e9;
    do
    {
        int32_t move = BFS(s, items.front());
        for(int32_t i = 0; i < items.size() - 1; ++i) {
            move += BFS(items[i], items[i + 1]);
        }
        move += BFS(items.back(), e);
        
        ans = min(ans, move);
    } while(next_permutation(items.begin(), items.end()));
    
    cout << ans;

    return 0;
}

그런데 λ‹€μ‹œ μƒκ°ν•΄λ³΄λ‹ˆ μ‹œμž‘ 지점, 도착 지점, 물건 지점 별 κ±°λ¦¬λŠ” κ³ μ •λ˜μ–΄ μžˆλ”λΌκ΅¬μš”. λͺ¨λ“  경우의 수 λ§ˆλ‹€ BFSλ₯Ό ν˜ΈμΆœν•΄μ„œ 거리λ₯Ό λ‹€μ‹œ 계산할 ν•„μš”λŠ” 없이, 졜초 1νšŒμ— ν•œν•΄ λͺ¨λ“  μœ„μΉ˜μ— λŒ€ν•œ μ΅œλ‹¨ 경둜 값을 미리 κ³„μ‚°ν•΄λ†“μœΌλ©΄ μˆœμ—΄μ„ μ΄μš©ν•΄ 경우의 수λ₯Ό λ”°μ§ˆ λ•Œ μΊμ‹±λœ 거리값을 μ΄μš©ν•˜λ©΄ 더 λΉ λ₯΄κ²Œ 계산할 수 μžˆκ² λ”λΌκ΅¬μš”.

C++

#include <bits/stdc++.h>
using namespace std;
using Vector2 = pair<int, int>;

enum : uint8_t {
    START = 'S',
    END   = 'E',
    ITEM  = 'X',
    EMPTY = '.',
    WALL  = '#',
};

const vector<Vector2> OFFSET = {
    {-1, 0}, {0, 1}, {1, 0}, {0, -1}
};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int M, N;
    cin >> M >> N;
    
    vector<vector<char>> house(N, vector<char>(M));
    Vector2 s, e;
    deque<Vector2> points;

    for (int i = 0; i < N; ++i) {
        for (int j = 0; j < M; ++j) {
            char c;
            cin >> c;
            house[i][j] = c;
            
            if(c == START) {
                s = {i, j};
            } else if(c == END) {
                e = {i, j};
            } else if(c == ITEM) {
                points.emplace_back(i, j);
            }
        }
    }
    
    points.emplace_front(s);
    points.emplace_back(e);
    
    auto isOutOfBound = [N, M](int i, int j) {
        return i < 0 || i >= N || j < 0 || j >= M;
    };

    auto BFS = [&house, N, M, &isOutOfBound](const Vector2 &src) {
        queue<Vector2> q;
        vector<vector<int>> d(N, vector<int>(M, -1));
        
        q.push(src);
        d[src.first][src.second] = 0;

        while (!q.empty()) {
            auto [i, j] = q.front();
            q.pop();
            for (const auto& [di, dj] : OFFSET) {
                int ni = i + di, nj = j + dj;
                if(isOutOfBound(ni, nj) || house[ni][nj] == WALL || d[ni][nj] > -1) {
                    continue;
                }
                
                d[ni][nj] = d[i][j] + 1;
                q.emplace(ni, nj);
            }
        }
        
        return d;
    };
    
    const int numPoints = points.size();
    const int INF = 1e9;
    vector<vector<int>> dist(numPoints, vector<int>(numPoints, INF));
    
    for(int u = 0; u < numPoints; ++u) {
        auto distFromSrc = BFS(points[u]);  // u번 지점(좜발/도착/물건듀 쀑 1개)μœΌλ‘œλΆ€ν„° λ‚˜λ¨Έμ§€ λͺ¨λ“  μ§€μ κΉŒμ§€μ˜ 거리가 μ €μž₯된 2차원 λ°°μ—΄
        for(int v = 0; v < numPoints; ++v) {
            const auto& [vi, vj] = points[v];
            if(u != v && distFromSrc[vi][vj] > -1) {
                dist[u][v] = distFromSrc[vi][vj];  // u-> v μ΅œλ‹¨ 거리 μ €μž₯
            }
        }
    }
    
    int ans = INF;
    if (points.size() == 2) {  // κ°€μ Έκ°€μ•Ό ν•  물건이 μ—†λ‹€λ©΄
        ans = dist[0][1];  // pointsλŠ” [S, E]만 쑴재
    } else {  // 물건이 μžˆλ‹€λ©΄
        vector<int> perm;
        for(int i = 1; i <= numPoints - 2; ++i) {  // S, [X1, X2, ..., Xi], K 쀑 물건듀에 λŒ€ν•œ 인덱슀 μΆ”μΆœ
            perm.emplace_back(i);
        }
        
        sort(perm.begin(), perm.end());
        
        do {
            int sum = dist[0][perm[0]];  // S -> 물건 1번
            for (int i = 0; i + 1 < perm.size(); ++i) {  // 물건 1번 -> 2번, 2번 -> 3번, ...
                sum += dist[perm[i]][perm[i + 1]];
            }
            
            sum += dist[perm.back()][numPoints - 1];  // λ§ˆμ§€λ§‰ 물건 -> E
            
            ans = min(ans, sum);  // 거리 ν•© 쀑 μ΅œμ†Œκ°’ 캐싱
        } while (next_permutation(perm.begin(), perm.end()));  // 물건 μΈλ±μŠ€λ“€μ„ μˆœμ—΄λ‘œ λͺ¨λ“  경우의 수 확인
    }

    cout << ans;
    return 0;
}

python

def solution(N, M, house):
    s, e = None, None
    p = []
    for i in range(N):
        for j, c in enumerate(house[i]):
            if c == 'S': 
                s = (i, j)
            elif c == 'E': 
                e = (i, j)
            elif c == 'X': 
                p.append((i, j))
            
            
    p = [s] + p + [e]
    pn = len(p)
    
    OFFSET = ((-1, 0), (0, 1), (1, 0), (0, -1))
    
    def bfs(src):
        q = deque([src])
        d = [[-1] * M for _ in range(N)]
        d[src[0]][src[1]] = 0
        
        while q:
            i, j = q.popleft()
            for di, dj in OFFSET:
                ni, nj = i + di, j + dj
                if (0 <= ni < N and 0 <= nj < M) and house[ni][nj] != '#' and d[ni][nj] == -1:
                    d[ni][nj] = d[i][j] + 1
                    q.append((ni, nj))

                
        return d
        
        
    INF = 10**9
    pn = len(p)
    dist = [[INF] * pn for _ in range(pn)]
    for u, src in enumerate(p):
        d = bfs(p[u])
        for v, dst in enumerate(p):
            vi, vj = dst
            if u != v and d[vi][vj] > -1:
                dist[u][v] = d[vi][vj]
                
                
    ans = INF
    items = list(range(1, pn - 1))
    if not items:
        ans = dist[0][1]
    else:
        for perm in permutations(items):
            total = dist[0][perm[0]]
            for a, b in zip(perm, perm[1:]):
                total += dist[a][b]
            total += dist[perm[-1]][pn - 1]
            ans = min(ans, total)

    return ans
    
    
def main(input):
    M, N = map(int, input().split())
    house = tuple(tuple(input().rstrip()) for _ in range(N))
    print(solution(N, M, house))


if __name__ == "__main__":
    from collections import deque
    from itertools import permutations
    main(open(0).readline)

Copy link
Collaborator

@hadongun hadongun left a comment

Choose a reason for hiding this comment

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

λΉ„νŠΈλ§ˆμŠ€ν‚Ήμ΄ μ΅μˆ™μΉ˜ μ•Šμ•„ κ·Έλƒ₯ visited 리슀트λ₯Ό μ΄μš©ν•΄ λ„μ „ν•΄λ³΄μ•˜μŠ΅λ‹ˆλ‹€

이전에 봀던 λ¬Έμ œλ“€μ€ 거리 ν…Œμ΄λΈ”μ΄ μ£Όμ–΄μ‘Œλ˜ 것 같은데
거리 ν…Œμ΄λΈ”μ„ 직접 ꡬ해야 ν•˜λŠ” κ²½μš°λŠ” 처음 λ³΄λŠ” 것 κ°™μ•„μš”!

κ·Έλž˜ν”„ 탐색을 쑰금 μ•Œκ²Œ 됐닀고 μƒκ°ν–ˆμ§€λ§Œ 더 μ—΄μ‹¬νžˆ ν•΄μ•Όκ² μŠ΄λ‘₯..

Details

from collections import deque
import sys
input = sys.stdin.readline

def bfs(sx, sy, board, N, M):
    visited = [[-1]*N for _ in range(M)]
    q = deque()
    q.append((sx, sy))
    visited[sy][sx] = 0

    while q:
        x, y = q.popleft()
        for dx, dy in [(0,1), (1,0), (0,-1), (-1,0)]:
            nx, ny = x + dx, y + dy
            if 0 <= nx < N and 0 <= ny < M and board[ny][nx] != '#' and visited[ny][nx] == -1:
                visited[ny][nx] = visited[y][x] + 1
                q.append((nx, ny))
    return visited

N, M = map(int, input().split())
board = [list(input().strip()) for _ in range(M)]

points = []
for i in range(M):
    for j in range(N):
        if board[i][j] == 'S':
            points.insert(0, (j, i))  
        elif board[i][j] == 'E':
            points.append((j, i))     
        elif board[i][j] == 'X':
            points.append((j, i))     

k = len(points) 

dist_table = [[-1]*k for _ in range(k)]
for i in range(k):
    visited = bfs(points[i][0], points[i][1], board, N, M)
    for j in range(k):
        x, y = points[j]
        dist_table[i][j] = visited[y][x]

min_total = sys.maxsize
visited = [False] * k

def dfs(now, depth, total):
    global min_total
    if depth == k - 2:  
        d = dist_table[now][k-1]  
        if d != -1:
            min_total = min(min_total, total + d)
        return

    for nxt in range(1, k - 1):  
        if not visited[nxt]:
            d = dist_table[now][nxt]
            if d == -1:
                continue
            visited[nxt] = True
            dfs(nxt, depth + 1, total + d)
            visited[nxt] = False

dfs(0, 0, 0)
print(min_total)

@froglike6 froglike6 merged commit 24c5f42 into main Jul 4, 2025
1 check passed
@dohyeondol1 dohyeondol1 deleted the 17-froglike6 branch July 13, 2025 15:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants