본문 바로가기

알고리즘 별 문제 정리/수학

[C++] 백준 1459: 걷기

문제 이해

- 학교에서 집까지 가려고 한다.

- 도시의 크기는 무한대이다.

- 도로는 수평으로 또는 수직으로 모두 존재한다. -> 수직선을 생각하자.

- 세준이의 현재 위치는 (0,0)이다.

- 세준이는 가로로 걷거나, 세로로 걷거나, 대각선으로 가로지를 수 있다.

- 집까지 가는 최소시간을 구하라.

 

<조건>

- 시간 제한: 2초

- 메모리 제한: 128MB

 

<입력>

- x, y: 집의 위치 (0 ~ 1,000,000,000, 10^9)

- w: 1블록을 가는데 걸리는 시간 (1 ~ 10,000, 10^4)

- s: 1블록을  가로지르는데 걸리는 시간 (1 ~ 10,000, 10^4)

 

<출력>

- 세준이가 집까지 가는데 걸리는 최소시간을 구하라.

 

 


문제 풀이

시작은 경우의 수를 나눠서 풀어야겠다고 생각했다.

세준이는 가로로 이동, 세로로 이동, 대각선으로 이동을 할 수 있기에

 

'평행 이동 시간'과 '대각선 이동 시간'을 비교하여

대각선 이동 시간이 작다면 대각선으로 최대한 이동해준 뒤에 평행 이동하였고,

아닐 경우 평행 이동으로만 이동시켰다.

 

 

그런데 

2 0 12 10

위의 예제 출력 결과가 이상함을 발견했다.

 

 

세준이의 위치를 편의상 (a, b)라고 표현하자.

처음 생각한 풀이는

a < x && b < y 일 때 대각선으로 이동시키는 것이었다.

즉, x좌표와 y좌표를 별개로 생각했던 것이다.

 

그런데 예제를 보고 생각해보니

대각선 이동을 위로 한 번, 아래로 한 번하여 2칸 이동하는게 효율적일 수 있었다...

 

 

30분정도 고민하다가 경우의 수를 제대로 파악하지 못해 인터넷 풀이를 참고하였다.

 

 

이 문제를 푸는 방법은 바로 3가지 경우로만 나누면 되었다.

1. 대각선으로만 이동

2. 평행 이동으로만 이동

3. 대각선 이동 + 평행 이동

 

 

1번의 경우는

long long ans1 = 0;
if((x+y) % 2 == 0){
    ans1 = max(x, y) * s;
}else{
    ans1 = (max(x, y) - 1) * s;
    ans1 += w;
}

위와 같았는데

여기서 핵심은 (x+y) % 2이다.

 

 

(x+y) % 2 ==0일 때,

min(x, y) * s + abs(x-y) * s = max(x, y) * s이다.

x + y가 짝수라면 abs(x-y)도 짝수이므로 가능한 식이다.

대각선 2번 이동으로 평행 이동 2번을 대체하는 것이다.

 

 

(x+y) % 2 == 1이라면,

max(x,y)-1만큼만 s로 이동하고

1칸은 w로 이동해줘야 할 것이다.

 

 

2번과 3번은 독자들도 쉽게 할 수 있을거라 생각한다.

 

1번, 2번, 3번의 결과 중 최솟값을 출력해주면 답이 된다.

 

 


주의할 점

1. 자료형을 long long으로 사용할 것.

x와 y의 최댓값이 10^9이고,

w와 s의 최댓값은 10^4이다.

 

둘을 곱하면 10^13으로 int형의 범위를 벗어나게 된다.

그러므로 자료형을 long long형으로 사용해야 된다는 걸 놓치지 말자.

 

 


전체 코드

#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;
#define INF 987654321

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);

    long long x, y, w, s;
    cin>>x>>y>>w>>s;

    long long ans1 = 0;
    if((x+y) % 2 == 0){
        ans1 = max(x, y) * s;
    }else{
        ans1 = (max(x, y) - 1) * s;
        ans1 += w;
    }

    long long ans2 = 0;
    ans2 = (x+y) * w;

    long long ans3 = 0;
    ans3 = min(x, y) * s;
    ans3 += (max(x, y) - min(x, y)) * w;

    cout<<min(ans1, min(ans2, ans3));
    return 0;
}

 

 


배운 점

1. 기본적인 수학 문제 공부의 필요성을 느낄 수 있었다.

2. 경우의 수 나누는 방식에 대해 배울 수 있었다.

'알고리즘 별 문제 정리 > 수학' 카테고리의 다른 글

[C++] 백준 1011: Fly me to the Alpha Centauri  (2) 2024.10.04
[C++] 백준 1629: 곱셈  (0) 2024.10.03