(✨✨✨✨✨ 별이 다섯개)조이스틱

·2026년 3월 27일

정답 코드

#include <string>
#include <vector>

using namespace std;

int solution(string name) {
    int answer = 0;
    
    
    // 유턴했을 때가 최고의 dist 나올 수 있다. 
    
    // ababaaaaaaabaaaaaaaaaaa
    
    // ababaaaaaaabaa
    
    // aaaaaaabab
    
    // abababaaaaaa
    // 그냥 오른쪽으로 가는게 좋은 경우 
    
    //      x               y
    // abababaaaaaaaaaaaaaaaba
    
    // 첫번재 b발견시 : 2번째 b로 가는 최소 값은 3이다.
    // 2번째 b 발견시 : 3번째 b로 가는 최소값은 3이다.
    // 3번째 b발견시  : 4번째 b로 가는 최소값은 8이다.
    
    // 그럼 내 생각에는 전부 더해야 하는 걸까? 
    // 굳이 누적을 해야 할까? 
    
    // 어차피 3번째 b로 가는 방법은 idx 로 오른쪽 이동, 다시 왼쪽으로 idx 이동 이후에
    // 끝으로 가는 방법이다. 
    
    // => 일단 누적을 하지 않음. 
    
        
    // 쉽게 진행하자.
    
    // 0123456789 101112
    // aabaaaaaaa  b a a : size : 13
    
    // 1번. 그냥 오른쪽으로 쭉 가기 
    // 2번. 유턴하기 
    // 아니면 이런것도 있다.
    // 뒤를 먼저 갔다가 앞으로 진행.
    
    
    // 10 (idx + diff) vs 2 + 2 + size() - 1 - 10 + 1
    // 8 vs 4 + 2 + 1
    
    // 8 vs 4 + 1
    
    //////////// 아래 걸로 증명 됨.
    
    
    // 0123456789 10 11 12 13 14 15
    // aaaabaaaaa  a a  a  a  b  b 
    // 전체 사이즈는 16
    
    // 오른쪽으로 쭉 이동하는 거는 안된다.
    
    // 오른쪽으로 갔다가 다시 u턴하기 
    // 쭉 오른쪽으로 가기 
    
    // 그냥 왼쪽으로 갔다가 다시 원점 지나서 오는거는?
    
    // 오른쪽 가는 거를 x라고 하고 ,
    // 왼쪽으로 가는 거를 y라고 하면 
    
    // 가) 4 + 4 + 16 - 14
    // 나) (16 -14) * 2 + 4
    
    // idx * 2 + size() - nextIdx 
    // ( size() - nextIdx) * 2 + idx;
    
    // 4번에서 14번으로 가는 방법
    
    // 14번에서 15번으로 가는 방법
    // 2개 중에서 매순간 최소값을 선택하기만 하면 된다. 
    
    // 왜냐하면 가번을 통해서 이미 오른쪽으로 가는 방법을 통해서 해결된다. 누적할 필요 없다
    
    int minValue = name.size() - 1;
    
    int ssize = name.size();
    for(int i = 0; i < name.size(); ++i)
    {
        
        // 상하로 이동하는 것만 처리하자. 
        int up = name[i] - 'A';
        int down = 'Z' - name[i] + 1;
        
        answer += min(up, down);
            
        int nextIdx = i + 1;
        
        while(nextIdx < ssize &&  name[nextIdx] == 'A')
        {
            nextIdx++;
        }
        
        // idx * 2 + size() - nextIdx 
        // ( size() - nextIdx) * 2 + idx;
        
        int right = i * 2 + ssize - nextIdx;
        int left = (ssize - nextIdx) * 2 + i;
        
        minValue = min(minValue, min(right, left));
        
    }
    answer += minValue;
    
    
    return answer;
}

아이디어가 중요하다...

https://4z7l.github.io/2021/03/12/algorithms-prg-42860.html

생각해보기

  1. 오른쪽으로 쭉 가기
  2. 오른쪽으로 쭉 가다가 원점으로 가서 왼쪽으로
  3. 왼쪽으로 갔다가 다시 원점으로 와서 오른쪽으로 진행?

누적에 대해서

  • 아래의 주석 내용을 보면, 누적을 할 필요가 없다.
  • 방정식
    : 타겟 idx + 타겟 idx + size() - 1 - 발견된 idx + 1(원점에서 꼬리로 가는 카운팅) 을 하면 된다.

  • 오른쪽으로 쭉 가는 방법은 할 필요 없다.

반례

  • 복귀를 해야 하고,

  • 나를 대상으로 뒤에 오는 value 중에 'a'가 아닌 값을 대상으로 확인하는 식으로 하면 이전에 오는 알파벳에 대해 생각할 필요 없다.
    -> 이미 완료된 상태다.

  • 2번째 나오는 b로 이동을 한다고 하자. 그러면 굳이 1번째 나오는 b의 왼쪽, 오른쪽 이동에 대해서 생각할 필요 없다.

핵심!

  • 빨간색 1번과 2번을 비교하고 있는데, b에 대해서는 생각할 필요가 없다.
  • 나중에 2번을 가지고 다음 pos에 오는 거를 확인할 것이다. 굳이 필요 없다!

수식을 작성하면서 해보자..

-> 규칙성이 보이면 수식화하려는 습관을 갖자.


최근 문제 풀이_260326 : 틀림

  • 잘못된 풀이

  • 반례가 있다.
    : 한쪽으로만 가능 코드로 하면 안된다. 이때는 유턴하는 것이 효율적이다.

결론 : 반례를 먼저 생각해보고 접근해야 한다.

  • 나의 생각인 2번과 3번에 대한 반례를 생각하는 시간을 가져야 한다.

  • 구글링.

그리디라고 판단되면?

  • 내가 생각한 해결전략에서 반례에 대해서 작성하자.

풀이전략

  • 풀다 보니 dp로 알파벳 a부터 z까지 타겟으로 잡은 값을 비교한 최소값을 넣어준 다음에 해야 효율이 좋겠구나 생각을 했지만, 이미 순차적으로 진행해서
    못 바꿈.
  1. 자리 이동하는 거 cur위치에서 타겟 자리로 좌측이동 vs 우측 이동한 값의 최소값을 구하고,
  2. 알파벳을 위로 이동 vs 아래로 이동 최소값을 구한다
  3. 1번과 2번의 값을 더한 값을 dp값에 넣어주고.
  4. 최종으로 다 더해주는 방법으로 진행했다.

// 반례

지금 내가 만든 반복문으로는 순차적으로 밖에 진행하지 못하지만,
반례를 보면 0번 인덱스 마치고, 마지막 인덱스로 이동해서 진행하는 것이
최소화 할 수 있다.
이 부분을 생각하지 못해서 만점아님..
추후에 다시 풀자...

profile
🔥🔥🔥

0개의 댓글