hyelie
hyelie
Hyeil Jeong
       
글쓰기    관리    수식입력
  • 전체보기 (495)
    • PS (283)
      • Algorithm (28)
      • PS Log (244)
      • Contest (6)
      • Tips (5)
    • Development (52)
      • Java (14)
      • Spring (23)
      • SQL (2)
      • Node.js (2)
      • Socket.io (3)
      • Study (4)
      • Utils (4)
    • DevOps (36)
      • Git (5)
      • Docker (4)
      • Kubernetes (2)
      • GCP (3)
      • Environment Set Up (8)
      • Tutorial (12)
      • Figma (2)
    • CS (74)
      • OOP (7)
      • OS (24)
      • DB (2)
      • Network (24)
      • Architecture (0)
      • Security (2)
      • Software Design (0)
      • Parallel Computing (15)
    • Project (15)
      • Project N2T (5)
      • Project ASG (0)
      • Project Meerkat (1)
      • Model Checking (7)
      • Ideas (2)
    • 내가 하고싶은 것! (34)
      • Plan (16)
      • Software Maestro (10)
      • 취준 (8)
hELLO · Designed By 정상우.
hyelie

hyelie

PS/PS Log

22.06.02. 풀었던 문제들

한 10일 쉰 것 같다! 그동안 탁구 배우면서 잘 쉬었던 것 같다. 외박도 다녀왔고 이제부터 다시 열심히 공부해야겠다!

​

1. 경주로 건설

일단 graph 문제이고, 최소값을 리턴하기 때문에 -> dijkstra를 사용해야만 한다. 그리고 v[max_r][max_c]를사용하는 것이 아니라, v[max_r][max_c][max_dire] 이렇게 3차원 배열로 풀어야만 하는 문제였다. 이렇게 해야 하는 이유는 반례가 있기 때문이다.

생각해 보자. (n, n) 좌표가 도착지점이다. 그리고 (n, n-1)지점이 (n, n)으로 갈 때 최솟값 경로에 속해있는 값이라 치자. 이 때, (n, n-2) 지점에서 오는 것과 (n-1, n-1)지점에서 올 때는 값이 달라질 수 있다. 아래 예제와 같이 (n-1, n-2) - (n-1, n-1) - (n, n-1)로 가면 (n, n-1)지점의 값이 3600이다. 그리고 (n, n-1)지점에서 (n, n) 지점으로 갈 때는 코너가 하나 더 생기기 때문에 4100이 된다 - 이 경우를 A경우라 두자.

그러나 (n, n-3) - (n, n-2) - (n, n-1)으로 가면 (n, n-1) 지점의 값은 3700이고, (n, n) 지점의 값은 3800이다. 이 경우를 B경우라 두자.

     
n-1
n
         
n-1
 
2900 ->
3000 |
 
n
3500 ->
3600 ->
위에서 내려오면 3600
왼쪽에서 오면 3700
도착지점
답은 3800

B경우가 optimal함에도 불구하고 2차원 배열로 각 element에 최소 cost만 저장해 버리면 위와 같은 반례가 생긴다. 따라서 '이전에 어떤 경로로 왔는지'에 대한 데이터가 필요하며 - 따라서 3차원 배열로 작성해야만 한다. 이 반례때문에 상-당히 골때렸다.

 

// 경주로 건설

#include <string>
#include <algorithm>
#include <vector>
#include <queue>

using namespace std;

typedef pair<int, int> pii;
struct rd{
    int row;
    int col;
    int dir;
};

int MAX = 2100000000, answer = MAX;
int dr[4] = {1, 0, -1, 0};
int dc[4] = {0, 1, 0, -1};
// 0 : down, 1 : right, 2 : up, 3 : left

int solution(vector<vector<int>> board) {
    int n = board.size();
    vector<vector<vector<int>>> road(n, vector<vector<int>>(n, vector<int>(4, MAX)));
    for(int i = 0; i<4; i++){road[0][0][i] = 0;};
    queue<rd> q;
    rd d; d.row = 0; d.col=0; d.dir=-1;
    q.push(d);
    while(!q.empty()){
        d = q.front(); q.pop();
        if(d.row == n-1 && d.col == n-1){
            answer = min(answer, road[n-1][n-1][d.dir]);
            continue;
        }
        for(int next_dir = 0; next_dir < 4; next_dir++){
            int next_r = d.row + dr[next_dir];
            int next_c = d.col + dc[next_dir];
            int cur_cost = road[d.row][d.col][d.dir];
            int next_cost = road[next_r][next_c][next_dir];
            if(0 > next_r || next_r >= n || 0 > next_c || next_c >= n || board[next_r][next_c] == 1 || next_cost < cur_cost) continue;
            
            cur_cost += 100;
            if(d.dir == 0 || d.dir == 2){
                if(next_dir == 1 || next_dir == 3){
                    cur_cost += 500;
                }
            }
            if(d.dir == 1 || d.dir == 3){
                if(next_dir == 0 || next_dir == 2){
                    cur_cost += 500;
                }
            }
            if(next_cost > cur_cost){
                road[next_r][next_c][next_dir] = cur_cost;
                rd n; n.dir = next_dir; n.row = next_r; n.col = next_c;
                q.push(n);
            }
            
        }
        
    }
    
    return answer;
}

 

2. 금과 은 운반하기

이것도 parametric search로 풀어야 하는 문제. 정답에 해당하는 시간은 long long으로 2^64, 매우 큰 값이지만 이분탐색 시 64번만에 해결 가능. 그리고 도시 개수는 10^5으로 조금 작은 편 => 시간으로 이분탐색하고 또한, 결정 문제로 바꾸었을 때 쉽게 풀릴 수 있으며, 가능한 답이 연속적(자연수)이기 때문에 parametric search임을 유추해내야 한다. 다만 결정 문제를 어떻게 풀지 조금 골때렸던 문제 + end를 LLONG_MAX로 두면 안 풀린다...?왤까 ㅋㅋㅋㅋ적당히 10^17로 바꾸면 된다. 왤까.... 그리고 항상 그렇듯 parametric search는 lower bound를 찾는 문제임을 인지!

// 금과 은 운반하기
bool isMoveable(int a, int b, vector<int> g, vector<int> s, vector<int> w, vector<int> t, ll totaltime){
    // 시간이 totaltime
    ll size = g.size();
    ll max_gold = 0, max_silver = 0, max_sum = 0;
    for(int i = 0; i<size; i++) {        
        ll num_move;
        if(totaltime < (ll)t[i]) continue; // 1번도 못옮기는 경우
        else{
            num_move = (totaltime - t[i]) / (2 * t[i]) + 1; // 여러 번 옮길 수 있는 횟수
        }
        ll move_amount = num_move * w[i];
        max_gold += min((ll)g[i], move_amount);
        max_silver += min((ll)s[i], move_amount);
        max_sum += min((ll)g[i] + s[i], move_amount);
    }
    if(max_gold >= a && max_silver >= b && max_sum >= a+b) return true;
    else return false;
}

long long solution(int a, int b, vector<int> g, vector<int> s, vector<int> w, vector<int> t) {
    ll start = 0, end = 1e17, mid;
    
    while(start < end){
        mid = (start + end) / 2;
        if(isMoveable(a, b, g, s, w, t, mid)){ // mid가 옮길 수 있다면
            end = mid;
        } else
            start = mid+1;
    }
    return end;
}

 

3. 최적의 행렬 곱셈

오랜만에 보는 DP. v[i][j]는 행렬 i~j까지 곱했을 때 최솟값이다. 그리고 이 v[i][j]는

i~i * i+1~j

i~i+1 * i+2~j

...

i~j-1 * j*j

의 행렬 곱의 최솟값으로 나온다. 그러면 k는 i부터 j-1까지 돌리면 될 것이다.

// 최적의 행렬 곱셈

#include <string>
#include <limits.h>
#include <algorithm>
#include <vector>

using namespace std;

int solution(vector<vector<int>> matrix_sizes) {
    int size = matrix_sizes.size();
    vector<vector<int>> v(size, vector<int>(size, 0)); // v[i][j] : i~j까지 곱 최솟값

    for(int len = 2; len<=size; len++){
        for(int i = 0; i<size-len+1; i++){
            int j = i + len - 1, min_value = INT_MAX;
            for(int k = i; k<j; k++){
                min_value = min(min_value, v[i][k] + v[k+1][j] + matrix_sizes[i][0] * matrix_sizes[k][1] * matrix_sizes[j][1]);
            }
            v[i][j] = min_value;
        }
    }
    
    
    // v[i][j] : min(i~k * k+1~j)
    
    return v[0][size-1];
}

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

22.06.04. 풀었던 문제들  (0) 2022.06.23
22.06.03. 풀었던 문제들  (0) 2022.06.23
22.05.22. 풀었던 문제들  (0) 2022.06.23
22.05.20. 풀었던 문제들  (0) 2022.06.23
22.05.19. 풀었던 문제들  (0) 2022.06.23
    hyelie
    hyelie

    티스토리툴바