정리충의 정리노트

[백준] 2618: 경찰차 본문

PS/DP

[백준] 2618: 경찰차

ioqoo 2020. 2. 29. 22:40

0. 문제 주소

 

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

 

2618번: 경찰차

첫째 줄에는 동서방향 도로의 개수를 나타내는 정수 N(5≤N≤1,000)이 주어진다. 둘째 줄에는 처리해야 하는 사건의 개수를 나타내는 정수 W(1≤W≤1,000)가 주어진다. 셋째 줄부터 (W+2)번째 줄까지 사건이 발생된 위치가 한 줄에 하나씩 주어진다. 경찰차들은 이 사건들을 주어진 순서대로 처리해야 한다. 각 위치는 동서방향 도로 번호를 나타내는 정수와 남북방향 도로 번호를 나타내는 정수로 주어지며 두 정수 사이에는 빈칸이 하나 있다. 두 사건이

www.acmicpc.net

 

 

1. 풀이

 

 

메모이제이션 없이 풀려면 2^1000가지 경우를 다 봐야 한다.

 

사건이 W개 있을 때, 0번째 사건이 (1, 1), 1번째 사건이 (N, N)에서 일어났다고 하고,

 

2번째 ~ W+1번째 사건의 좌표를 저장해둔다.

 

다음 dp 테이블의 정의를 아래와 같이 한다.

 

dp[i][j] = 경찰차1이 i번째 사건, 경찰차2가 j번째 사건을 해결한 상황일 때, 앞으로의 이동거리 중 최솟값

 

다음 solve 함수를 아래와 같이 설계한다.

 

int solve(int a, int b){
    int curr_num = max(a, b) + 1;
    if (curr_num == W+2) return 0;
    
    int &ret = dp[a][b];
    if (ret != -1) return ret;
    
    int X = solve(curr_num, b) + dist(task[a], task[curr_num]);
    int Y = solve(a, curr_num) + dist(task[b], task[curr_num]);
    if (X < Y) ans[a][b] = 1;
    else ans[a][b] = 2;
    
    return ret = min(X, Y);
}

 

현재 경찰차 1이 a번, 경찰차 2가 b번 사건을 해결했다면, 다음에 해결해야 할 사건의 번호는

 

curr_num = max(a, b) + 1이 된다.

 

경찰차 1과 경찰차 2 각각을 curr_num번 사건을 해결하게 하고. 둘 중 더 작은 값을 dp[a][b]에 저장해준다.

 

추가적으로 트래킹을 위해 "ans[a][b] = 각각 a, b번 사건을 처리한 상황일 때, 다음 사건을 처리할 번호"를 저장해준다.

 

 

맨 처음엔 ans 배열을 1차원으로 짜고 curr_num번째 사건을 처리할 경찰 번호를 저장해줬는데

 

이 경우 각각의 경우마다 매번 ans[curr_num]이 갱신되어서 최적의 해를 저장하지 못하는 문제가 생긴다.

 

2. 풀이 코드

 

* 유의할 점

 

 

#include <iostream>
#include <vector>
#include <cstring>
#include <algorithm>

#define pii pair<int, int>
#define MAX 1005

using namespace std;

int N, W;
pii task[MAX];
int dp[MAX][MAX];
int ans[MAX][MAX];

int dist(pii A, pii B){
    return abs(A.first - B.first) + abs(A.second - B.second);
}

int solve(int a, int b){
    int curr_num = max(a, b) + 1;
    if (curr_num == W+2) return 0;
    
    int &ret = dp[a][b];
    if (ret != -1) return ret;
    
    int X = solve(curr_num, b) + dist(task[a], task[curr_num]);
    int Y = solve(a, curr_num) + dist(task[b], task[curr_num]);
    if (X < Y) ans[a][b] = 1;
    else ans[a][b] = 2;
    
    return ret = min(X, Y);
}

int main(){
    #ifndef ONLINE_JUDGE
    freopen("input.txt", "r", stdin);
    #endif
    
    scanf("%d %d", &N, &W);
    
    memset(dp, -1, sizeof(dp));
    
    task[0] = pii(1, 1);
    task[1] = pii(N, N);
    int x, y;
    for (int i=2;i<=W+1;i++){
        scanf("%d %d", &x, &y);
        task[i] = pii(x, y);
    }
    
    printf("%d\n", solve(0, 1));
    
    for (int x=0, y=1; max(x, y)+1 <= W+1; ){
        printf("%d\n", ans[x][y]);
        if (ans[x][y] == 1) x = max(x,y) + 1;
        else y = max(x, y) + 1;
    }
    
    return 0;
}

 

 

 

'PS > DP' 카테고리의 다른 글

[백준] 3948: 홍준이의 친위대  (0) 2020.08.18
[백준] 10714: 케이크 자르기 2  (0) 2020.02.29
[백준] 1103: 게임  (1) 2020.02.03
[백준] 2624: 동전 바꿔주기  (0) 2020.01.28
[백준] 1256: 사전  (0) 2020.01.28
Comments