프로그래밍 공부
작성일
2024. 2. 29. 17:31
작성자
WDmil
728x90

문제 설명

프로그래머스의 마스코트인 머쓱이는 최근 취미로 당구를 치기 시작했습니다.

 

머쓱이는 손 대신 날개를 사용해야 해서 당구를 잘 못 칩니다. 하지만 끈기가 강한 머쓱이는 열심히 노력해서 당구를 잘 치려고 당구 학원에 다니고 있습니다.

 

오늘도 당구 학원에 나온 머쓱이에게 당구 선생님이"원쿠션"(당구에서 공을 쳐서 벽에 맞히는 걸 쿠션이라고 부르고, 벽에 한 번 맞힌 후 공에 맞히면 원쿠션이라고 부릅니다) 연습을 하라면서 당구공의 위치가 담긴 리스트를 건네줬습니다. 리스트에는 머쓱이가 맞춰야 하는 공들의 위치가 담겨있습니다. 머쓱이는 리스트에 담긴 각 위치에 순서대로 공을 놓아가며 "원쿠션" 연습을 하면 됩니다. 이때, 머쓱이는 항상 같은 위치에 공을 놓고 쳐서 리스트에 담긴 위치에 놓인 공을 맞춥니다.

 

머쓱이와 달리 최근 취미로 알고리즘 문제를 풀기 시작한 당신은, 머쓱이가 친 공이 각각의 목표로한 공에 맞을 때까지 최소 얼마의 거리를 굴러가야 하는지가 궁금해졌습니다.

 

당구대의 가로 길이 m, 세로 길이 n과 머쓱이가 쳐야 하는 공이 놓인 위치 좌표를 나타내는 두 정수 startX, startY, 그리고 매 회마다 목표로 해야하는 공들의 위치 좌표를 나타내는 정수 쌍들이 들어있는 2차원 정수배열 balls가 주어집니다. "원쿠션" 연습을 위해 머쓱이가 공을 적어도 벽에 한 번은 맞춘 후 목표 공에 맞힌다고 할 때, 각 회마다 머쓱이가 친 공이 굴러간 거리의 최솟값의 제곱을 배열에 담아 return 하도록 solution 함수를 완성해 주세요.

 

, 머쓱이가 친 공이 벽에 부딪힐 때 진행 방향은 항상 입사각과 반사각이 동일하며, 만약 꼭짓점에 부딪힐 경우 진입 방향의 반대방향으로 공이 진행됩니다. 공의 크기는 무시하며, 공의 좌표가 정확히 일치하는 경우에만 두 공이 서로 맞았다고 판단합니다. 공이 목표 공에 맞기 전에 멈추는 경우는 없으며, 목표 공에 맞으면 바로 멈춘다고 가정합니다.

 

 

위 그림은 친 공이 벽에 맞았을 때의 움직임을 나타낸 그림입니다. 치기 전 공의 위치가 점 A입니다.

 

 

위 그림은 친 공이 꼭짓점에 맞았을 때의 움직임을 나타낸 그림입니다. 치기 전 공의 위치가 점 A입니다.

 

제한사항

  • 3 ≤ m, n ≤ 1,000
  • 0 < startX < m
  • 0 < startY < n
  • 2 ≤ balls의 길이 ≤ 1,000
  • balls의 원소는 [a, b] 형태입니다.
  • a, b는 머쓱이가 맞춰야 할 공이 놓인 좌표를 의미합니다.
  • 0 < a < m, 0 < b < n
  • (a, b) = ( startX, startY )인 입력은 들어오지 않습니다.

입출력 예

m n startX startY balls result
10 10 3 7 [[7, 7], [2, 7], [7, 3]] [52, 37, 116]

문제 해설

 

조건항이랑 문제 수식을 생각해야 한다.

 

가장 짧은 대칭선을 그려야 하나, 쿠션을 무조건 쳐야 하기 때문에, 목표 당구공이 같은 선분 상에 놓여있으면 해당 방향의 각도에 제한이 생긴다.

 

문제수식의 경우, 대칭점과 대칭선을 생각하면 된다. 쿠션 한번을 기준으로 당구공 과 당구공간의 최단거리를 계산하는것 은, 쿠션을 한 면 기준으로 대칭돤 목표당구공의 위치의 선분과 같다.

위와같은 상솽일 때, B와 B'의 거리는 같다.


첫 번째 시도

#include <string>
#include <vector>
#include <cmath>
#include <algorithm>

using namespace std;

int Distance(const vector<int>& v1, const vector<int>& v2, const vector<int>& p)
{

    vector<int> mir({v2[0] + p[0]*2, v2[1] + p[1]*2});
    if (v1[0] == mir[0] || v1[1] == mir[1])
        return 1000000000;
    return pow(v1[0] - mir[0], 2) + pow(v1[1] - mir[1], 2);
}

int ReturnToMinDistance(const vector<int>& i1, const vector<int>& i2, int m, int n)
{
    vector<int> UpPoint({ 0, n - i2[1]});
    vector<int> DownPoint({ 0, -i2[1]});
    vector<int> LeftPoint({ -i2[0], 0});
    vector<int> RightPoint({ m - i2[0], 0 });

    vector<double> resultvector;
    resultvector.emplace_back(Distance(i1, i2, UpPoint));
    resultvector.emplace_back(Distance(i1, i2, DownPoint));
    resultvector.emplace_back(Distance(i1, i2, LeftPoint));
    resultvector.emplace_back(Distance(i1, i2, RightPoint));
    return *min_element(resultvector.begin(), resultvector.end());
}

vector<int> solution(int m, int n, int startX, int startY, vector<vector<int>> balls) {
    vector<int> answer;
    for (auto& def : balls)
        answer.emplace_back(ReturnToMinDistance({startX, startY},def,m, n));
    return answer;
}

실패

 

대칭선 기준으로 거리계산을 했는데, 틀렸다. 왜그런지 이유가 몰라서 찾아봐야함.


두 번째 시도

#include <string>
#include <vector>
#include <cmath>
#include <algorithm>

using namespace std;

int CalculateDistance(const vector<int>& v1, const vector<int>& v2, const vector<int>& p)
{
    vector<int> mir({v2[0] + (p[0] - v2[0]) * 2, v2[1] + (p[1] - v2[1]) * 2});

    if (v1[0] == mir[0] || v1[1] == mir[1])
        return numeric_limits<int>::max();

    return pow(v1[0] - mir[0], 2) + pow(v1[1] - mir[1], 2);
}

int ReturnToMinDistance(const vector<int>& i1, const vector<int>& i2, int m, int n)
{
    vector<int> UpPoint({ i2[0], n });
    vector<int> DownPoint({ i2[0], 0});
    vector<int> LeftPoint({ 0, i2[1] });
    vector<int> RightPoint({ m, i2[1] });

    vector<double> resultvector;
    resultvector.emplace_back(CalculateDistance(i1, i2, UpPoint));
    resultvector.emplace_back(CalculateDistance(i1, i2, DownPoint));
    resultvector.emplace_back(CalculateDistance(i1, i2, LeftPoint));
    resultvector.emplace_back(CalculateDistance(i1, i2, RightPoint));
    return *min_element(resultvector.begin(), resultvector.end());
}

vector<int> solution(int m, int n, int startX, int startY, vector<vector<int>> balls) {
    vector<int> answer;
    for (auto& def : balls)
        answer.emplace_back(ReturnToMinDistance({startX, startY},def,m, n));
    return answer;
}

실패

 

rimit값이 문제인것 같아. 최종값을 numeric_limits<int>로 하였는데 틀렸다. 이 문제가 아닌것같다.


세 번째 시도

#include <string>
#include <vector>
#include <cmath>
#include <algorithm>

using namespace std;

int CalculateDistance(const vector<int>& v1, const vector<int>& v2, const vector<int>& p)
{
    vector<int> mir({ v2[0] + (p[0] - v2[0]) * 2, v2[1] + (p[1] - v2[1]) * 2 });
    return pow(v1[0] - mir[0], 2) + pow(v1[1] - mir[1], 2);
}

int ReturnToMinDistance(const vector<int>& i1, const vector<int>& i2, int m, int n)
{
    vector<int> resultvector;
    if (!(i1[1] < i2[1] && i1[0] == i2[0]))
        resultvector.emplace_back(CalculateDistance(i1, i2, { i2[0], n }));
    if (!(i1[1] > i2[1] && i1[0] == i2[0]))
        resultvector.emplace_back(CalculateDistance(i1, i2, { i2[0], 0 }));
    if (!(i1[0] > i2[0] && i1[1] == i2[1]))
        resultvector.emplace_back(CalculateDistance(i1, i2, { 0, i2[1] }));
    if (!(i1[0] < i2[0] && i1[1] == i2[1]))
        resultvector.emplace_back(CalculateDistance(i1, i2, { m, i2[1] }));
    return *min_element(resultvector.begin(), resultvector.end());
}

vector<int> solution(int m, int n, int startX, int startY, vector<vector<int>> balls) {
    vector<int> answer;
    for (auto& def : balls)
        answer.emplace_back(ReturnToMinDistance({startX, startY},def,m, n));
    return answer;
}

성공

 

대칭선 문제가 아니라, 수식상 좌측 우측 상 하 계산을 할 때, 목표 당구공과 현재 당구공이 맞닿는지 확인하는 코드를 작성해야 한다.

 

모든 수식상 제한사항이 단 한개 뿐 임으로, 해당 제한을 확인해야할 필요가 있었음.

 

카카오 윈터인턴십 코테문제 레벨 3인가 4가 풀 때 4점을 주는데, 이거는 6점을 줌..

728x90