JonghoonAn
어제보다 하나 더
JonghoonAn
전체 방문자
오늘
어제
  • 분류 전체보기
    • 알고리즘
    • 프로젝트
    • 배운점
    • ML
    • 학교 공부
      • OS
      • 네트워크
      • 시스템 프로그래밍
      • 데이터베이스
      • 소프트웨어 분석 및 설계

블로그 메뉴

  • 홈
  • 알고리즘
  • 배운점
  • 학교 공부
  • 머신러닝

공지사항

인기 글

태그

  • lecture6
  • 가중치 초기화
  • 인공신경망
  • convolutional neural network
  • 인공지능
  • Backpropagation
  • 인공 신경망
  • lecture10
  • 활성화 함수
  • 전이 학습
  • pooling
  • lecture7
  • Learning rate
  • activation function
  • conv
  • Transfer learning
  • neural network
  • lecture9
  • rnn
  • 역전파
  • cs231n
  • 학습률
  • convolutional layer
  • 합성곱
  • CNN Architecture
  • 인공지능 학습
  • ConvNets
  • recurrent network
  • CS231
  • convolutional network

최근 댓글

최근 글

티스토리

JonghoonAn

어제보다 하나 더

백준 10879번 Speak your mind!
알고리즘

백준 10879번 Speak your mind!

2021. 7. 9. 11:35

문제

문제 분석

복잡해 보이지만, 결국 요점은 입력을 2의 제곱의 덧셈 뺄셈으로 나타내는 것이다. 현재 값이 A라고 할 때 A를 X(2의 제곱수) - Y(나머지) 혹은 X'(2의 제곱수) + Y'(나머지)로 나타내고, 그 중에서 작은 값을 선택하면 된다. 이를 점화식으로 나타내면 다음과 같다.

 

N(A) = min((N(X/2)+N(A-X/2)+4), (N(X)+N(X-A)+4))

 

나는 이를 DP + DFS로 풀었다. 좀 더 디테일 하게 설명해보자면,  DP를 확인하여 값이 있으면 그 값을 리턴하고, 없으면 재귀 호출로 쭉 내려가서 값을 계산하여 그를 사용하는 방식 말이다. 내가 이렇게 한 이유는 A보다 큰 값이 문제 해결에 쓰이기 때문이었다(A = X - Y). 그런데 다시 보니, X는 A보다 크더라도 2의 제곱이 분명하므로 별다른 연산 없이 DP에 값이 존재하고, Y는 A보다 작다. 따라서 DFS를 이용한 재귀호출보다는 그냥 쌩 DP만 이용해서 풀었어도 됐을 것 같았다. 실제로, 다른 분들의 결과를 보니 400ms였던 나의 알고리즘에 비해 40ms에 분포해있었고, 모두 쌩 DP로 푼 경우였다.

 

가장 햇갈렸던 점은 0에 대한 처리이다. 처음에는 걍 안해줬다가, 0의 재귀 호출이 반복되면서 메모리 초과 오류가 떴고, 0이 문제인것 같아서 0으로 초기화해줬더니 틀렸다고 떴다. 생각해보니 0은 문장에 단어가 없는 것이 아닌 -1 + 1이라는 특수한 경우였고, 이를 규칙에 따라 6으로 초기화 해주었더니 문제가 해결돼었다.

 

코드

// code
#include<stdlib.h>
#include<iostream>
#include<string.h>
#include<string>
#include<list>
#include<vector>
#include<stack>
#include<queue> // priority_queue 포함
#include<set>
#include<unordered_set>
#include<map>
#include<unordered_map>

#include<algorithm>
#include<math.h>
#include<climits> // 자료형 limit포함

using namespace std;

typedef long long int lld;
typedef unsigned long long int uld;
typedef unsigned int ui;

const int MY_INT_MAX = 2000000000;

int DP[50001] = {0};


int dfs(int param_d)
{
    if(DP[param_d] != 0 || param_d == 0)
        return DP[param_d];

    int tmp_exp = 1;
    while(param_d / tmp_exp > 0)
        tmp_exp *= 2;
    
    int return_val = MY_INT_MAX;
    if(tmp_exp == 65536)
        return_val = min(return_val, (DP[tmp_exp/2]+1) +  dfs(tmp_exp - param_d) + 4);
    else
        return_val = min(return_val, DP[tmp_exp] +  dfs(tmp_exp - param_d) + 4);
    return_val = min(return_val, DP[tmp_exp/2] +  dfs(param_d - tmp_exp/2) + 4);
    DP[param_d] = return_val;
    return return_val;
}

void solution()
{
    // code
    int n;
    cin >> n;
    int init_d = 1;
    int init_count = 1;
    while(init_d <= 50001)
    {
        DP[init_d] = init_count;
        init_d *= 2, init_count++;
    }
    DP[0] = 6;

    for(int i=0; i<n; i++)
    {
        int target_d;
        cin >> target_d;
        target_d = abs(target_d);
        int out_val = dfs(target_d);
        cout << out_val << endl;
    }
}

int main ()
{
    iostream::sync_with_stdio(0); // 이제 C stdio의 입출력 사용 불가
    cin.tie(NULL);
    cout.tie(NULL); // 개행도 \n로 하도록 하자.
    solution();
    return 0;
}

개선점?

점화식으로 나타내보는것이 매우 중요한것 같다. 재귀호출로 구현은 매우 쉬웠지만, 이것을 점화식으로 직접 써보지 않아서 쌩 DP로 풀 수 있는 직관을 얻지 못했던 것 같다.

아이디어 -> 점화식 -> 알고리즘 -> 알고리즘 복잡도 평가

요런 방식으로 풀어야할것 같다.

 

저작자표시 비영리 변경금지 (새창열림)

'알고리즘' 카테고리의 다른 글

백준 17370번 육각형 우리 속의 개미  (0) 2021.07.09
백준 14003 번 : 가장 긴 증가하는 부분 수열 5  (0) 2021.05.19
백준 1238 : 파티 / 플로이드 워셜 알고리즘  (0) 2021.05.19
백준 20543 번 : 폭탄 던지는 태영이 / 2D prefix-sum  (1) 2021.05.19
2020 카카오 인턴십 for Tech developers 코딩테스트 3번  (0) 2021.05.07
    '알고리즘' 카테고리의 다른 글
    • 백준 17370번 육각형 우리 속의 개미
    • 백준 14003 번 : 가장 긴 증가하는 부분 수열 5
    • 백준 1238 : 파티 / 플로이드 워셜 알고리즘
    • 백준 20543 번 : 폭탄 던지는 태영이 / 2D prefix-sum
    JonghoonAn
    JonghoonAn
    https://github.com/jjong0225 숭실대 소프트
    hELLO. 티스토리 스킨을 소개합니다.
    제일 위로

    티스토리툴바