관리 메뉴

어읽로꾸거

BOJ 16118 달빛여우 본문

알고리즘

BOJ 16118 달빛여우

어읽로꾸거 2019. 3. 30. 14:35

백준 16118 링크

https://www.acmicpc.net/problem/16118

정말 어렵게 풀었습니다 😣

대략 이 문제를 접한지 2~3주 만에 풀었습니다. 처음엔 금방 풀 수 있을줄 알았는데 그게 아니었습니다. 여러 사람들에게 물어보고 또 질문하고, 다시 한번 물어보고(이해가 안되서 물어봄), 생각해보고. 그러던 끝에, 해답을 알게 되었습니다. 이제와서 생각해보니 크게 어려운건 아닌거같기도 하고 🙄

처음에 접근한 방법

다익스트라 문제인건 알겠는데 어떻게 해결하지?

 

아하, 여우와 늑대가 다익스트라 하는것을 각각 따로 만들어서 해주면 되겠지.

 

그냥 여우 거리 배열(dp_f[]),늑대 거리 배열(dp_w[]) 만들어서 하면 될꺼야.

 

그러면 처음엔 느리다가 나중에 빨라지는 경우를 구할 수 가 없게 됩니다. 🤔

 

어떻게 하지??

문제 풀이

여우는 그냥 다익스트라로 구하면 되니까 더 건들 필요는 없을꺼고 늑대를 조금 더 건들면 될거같은데.

 

늑대 다익스트라를 빠른 경우와 느린 경우로 나눠주고 거리 배열도 빠를 때(dp_wf[])와 느릴 때(dp_ws[])로 나눠봅시다.

 

느리게 움직일때는 dp_ws[] 와 dp_wf[] + (가중치/2)를 비교하고 큐에 다음에 빠르게 움직이도록 psuh

 

빠르게 움직일때는 dp_wf[] 와 dp_ws[] + (가중치*2)를 비교하고 큐에 다음에 느리게 움직이도록 psuh

 

이렇게 하면 빠를때와 느릴때 각각 최소로 움직이는 경우를 구할 수 있습니다.

이렇게 하면 된줄 알았죠?

저도 이렇게 하면 된줄 알고 제출을 했는데 시간제한이라고 알려줍니다. 😨

 

다익스트라에서 시간을 줄이는 방법은 지금 큐에서 꺼낸 노드의 가중치와 dp에 기록된 가중치가 같은지 확인하는 절차를 거치면 시간이 조금 줄어듭니다.

if(cost != dp[now]) continue;

같다면 진행하고 같지 않다면 지금 가중치는 의미가 없을테니 넘어갑시다.

 

다른 사람들한테 알고리즘 설명해주는걸 정말 좋아합니다. 혹시 저의 글이 부족하다고 생각되면 꼭 댓글로 리뷰나 질문부탁드릴게요.

코드

#include<iostream>
#include<queue>
#include<vector>
#include<string.h>
using namespace std;
typedef struct wolf {
    int record; 
    int node;
    bool fast; //0은 느림 1은 빠름
};
bool operator < (wolf a, wolf b) {
    return a.record < b.record;
}
int n, m;
int dp_f[4003], dp_wf[4003], dp_ws[4003]; 
vector <pair<int, int>> con[4003];
priority_queue <wolf> wolf_q;
priority_queue <pair<int, int>> fox_q;
int min(int a, int b) {
    return a < b ? a : b;
}
int main() {
    //    freopen("input.txt", "r", stdin);
    scanf("%d %d", &n, &m);
    while (m--) {
        int a, b;
        int c;
        scanf("%d %d %d", &a, &b, &c);
        con[a].push_back({ b,c * 2 }); //이 부분에서 가중치를 2배로 받음
        con[b].push_back({ a,c * 2 }); //이 부분에서도
    }
    for (int i = 1; i <= n; i++) dp_f[i] = dp_ws[i] = dp_wf[i] = 2e9;
    
    //여우 다익스트라
    dp_f[1] = 0;
    fox_q.push({ 0,1 });
    while (!fox_q.empty()) {
        int cost = -1 * fox_q.top().first;
        int now = fox_q.top().second;
        fox_q.pop();
        if (cost != dp_f[now]) continue;
        for (auto i : con[now]) {
            int next = i.first;
            if (dp_f[now] + i.second < dp_f[next]) {
                dp_f[next] = dp_f[now] + i.second;
                fox_q.push({ -1 * dp_f[next], next });
            }
        }
    }
    //여우 다익스트라
    
    //늑대 다익스트라
    wolf_q.push({ 0,1,true });
    dp_ws[1] = 0;
    while (!wolf_q.empty()) {
        int now = wolf_q.top().node;
        int record = -1 * wolf_q.top().record;
        bool fast = wolf_q.top().fast;
        wolf_q.pop();
        if (fast) {
            if (dp_ws[now] != record) continue;
        }
        else {
            if (dp_wf[now] != record) continue;
        }
        for (auto i : con[now]) {
            if (fast) { //늑대가 빠르게갈때는 가중치 반으로 해서 더해줌
                int next = i.first;
                if (dp_ws[now] + (i.second / 2) < dp_wf[next]) {
                    dp_wf[next] = dp_ws[now] + (i.second / 2);
                    wolf_q.push({ -1 * dp_wf[next],next, false });
                }
            }
            else { //늑대가 느리게 갈때는 가중치 2배로 해서 더해줌
                int next = i.first;
                if (dp_wf[now] + (i.second * 2) < dp_ws[next]) {
                    dp_ws[next] = dp_wf[now] + (i.second * 2);
                    wolf_q.push({ -1 * dp_ws[next],next, true });
                }
            }
        }
    }
    //늑대 다익스트라
    
    int ans = 0;
    for (int i = 1; i <= n; i++) {
        if (dp_f[i] < min(dp_wf[i], dp_ws[i])) ans++;
    }
    printf("%d", ans);
}

'알고리즘' 카테고리의 다른 글

BOJ 4287 Word Ratios  (0) 2019.04.01
BOJ 2504 괄호의 값  (0) 2019.03.31
BOJ 16469 소년 점프  (0) 2019.03.28
BOJ 16953 A → B  (0) 2019.03.27
BOJ 1932 정수 삼각형  (0) 2019.03.26