H. Polynomial BOJ 11500

 

 문제 설명 :

 

  어떤 함수 f(k)를 아래와 같이 정의한다. 

 

 

 이 때 우리는 f에 관한 새로운 식 S(n)을 정의할 건데 그건 또 아래와 같다.

 

이럴 때 S(n)을 n에 관하여 정리해보자면 아래와 같이 정리된다.

 

 

이 때 다음을 구해서 출력하시오.

 

주어지는 것은 다음이다. 

 

 

문제 풀이 :

 

 사실 이런 종류의 수식을 처음 접하는 사람은 이게 대체 뭔 개소린가 싶은 느낌이 들 것이다. 정수론과 굉장히 밀접한 식인데 처음 읽었을 때 도무지 분석을 할 수가 없었다.

 

 S(n)을 f(k)로 풀어보자면 다음과 같다.

일단, 

이식을 보면 이걸 n에 관하여 정리해야 하는데, 정수론에 대해 기초 지식이 있는 사람들은 (사실 고딩때도 배운다) 거듭제곱의 합이 n에 관한 식으로 나온다는 사실을 알 수 있다. 

 

 

예를들면,

 

요런 것들? 

 

따라서 거듭제곱이 같은 것끼리 모아보자.

위 식을 정리하면 아래와 같이 깔끔하게 나오게 된다.

 

 

이제 필요한게 0<=t<=25 사이에 있는 모든 거듭제곱의 합의 계수들만 찾으면 답이다.

 

근데이게 쉽지가 않다. 이 걸 찾기 위해서는 가장 마지막에 주어진 식이 필요하다.

 

 

1부터 n까지 k제곱의 합을 앞으로 T(n,k)라 했을 때 다음과같다.

^증명보시려면 클릭하세요.

 

위 식을 정리하고나면 0~k-1의 거듭제곱합을 통해서 k거듭제곱합을 구할 수 있다.

따라서 0,1,2,3,4...25까지 미리 거듭제곱의 합을 구해놓고 처리하면 끝

 

소스코드 보기 <- 클릭

문제집 : https://www.acmicpc.net/category/detail/1413

풀이는 하나하나 업데이트 될 예정입니다.

간략한 문제 분류와 솔루션만 제시 해놓고 풀이가 따로 필요하다고 생각되는 문제들은 추후 링크 하도록 하겠습니다. (요청하시면 그 부분에 관한 풀이도 올려드리겠습니다. ) 


A. Coin Swap  BOJ 11493


 flow문제 중에서도 MCMF문제다.  "동전의 교환 = 코스트" 로 두고 흰색을 모두 흰색으로 옮길때의 최소 코스트로 그래프 설계를 하면 된다.(검은색을 검은색으로 옮기는 코스트로 생각해도 무방) 흰색 정점이 있는 곳을 src와 연결하고 흰색 동전이 있는 곳을 sink로 돌렸을 때 나오는 MCMF결과를 출력하면 된다.


C. Grid BOJ 11495


 flow 문제 중에서도 이분 그래프로 만든 후 최대매칭하는 문제다. 익히 알려진 사실로 최대 매칭은 flow와 동치다.
 각각의 그리드를 순서대로 1, 2, 3,4... 번호를 매긴 후 인접한 것 끼리 연결한다. 이때 짝수는 src에 홀수는 sink에 연결하며 각각의 캐퍼시티는 그 그리드의 값으로 하고 매칭을 찾으면 된다.
 이 때 결과를 찾는 방법은 두가지 있는데 src와 sink에 남아 있는 캐퍼시티를 추적하는 방법과 전체에서 매칭의 수를 빼는 방법이 있다.(1매칭은 1코스트를 감소시켜주므로) 


D. Kernel  BOJ 11496


 기하 문제다.(segment tree로도 풀린다고 한다.) kernel이 존재할 수 있는 구간을 결정하고 그 위치가 주어진 polygon사이에 존재하는 지 결정하는 문제다. 열심히 그려보다보면 어떤 방식으로 kernel이 존재할 수 있는 구간을 결정하는 지 알 수 있다.(솔직히 이런걸 대회중에 발견하기는 어려워 보인다..)


E. Log Jumping BOJ 11497


 그리디 문제다. 통나무들을 길이 순으로 정렬하고 원의 왼쪽 오른쪽 차례대로 배치해 나가면 최적이 된다. 


F. Odd Cycle BOJ 11498


 그래프 문제 중에서도 SCC를 사용하여 시간을 줄이는 문제다. 사실 진짜 별거 없고 coloring하는데 그 coloring을 SCC내에서 하면 되는 문제다. 근데 한가지 조심해야할게 그냥 돌리면 WA가 날 수 있는데 사이클이 여러개 존재할 수 있다. 따라서 coloring을 back edge만 체크하게 해야한다. 이때 잘 처리 해줘야 TLE가 안난다. 


G. Path BOJ 11499


 기하 문제 중에서도 Convex_hull을 사용하는 문제다. 사실 그냥 컨백스 홀 만드는 방식으로 그냥 쭉 훑으면서 만들면서 최대 값을 갱신만 시켜주면된다.


H. Polynomial BOJ 11500 솔루션


 그냥 수식을 정리하는 문제다. 수학적 센스가 필요한 것 같다. (이미 알고 있다면 개꿀이었을 듯...) 수식을 정리해서 그대로 대입하면 된다. (하루종일 정리하면 된다.) 거듭 제곱의 합에 관하여 정리해야 한다.


I. Stock BOJ 11501


 파라매트릭 서치 문제다. 특정 상한을 결정하고 만들 수 있는지 검사한다. 이 때 검사는 선형으로 할 수 있어서 O(n) 그리고 파라매트릭에 logn이 들어 총 O(nlogn)이 든다. 


J. 3-Primes Problem BOJ 11502

 

 추측이라는데 그런가 보다 하면 된다. 그냥 하라는데로 하면 되는데 1000밖에 안된다. 따라서 소수 a,b를 결정하면 자동으로c가 결정된다. 여러가지 방법이 있는데, 전수 검사를 해서 (a,b,결정하고 c가 소수인지 확인) 푸는 방법, 넵섹하는 법, 등등 있다.


K. Tree Edit BOJ 11503


트리 dp문제다. 아직 안풀었다.


 L. Wheel of Numbers BOJ 11504


시뮬레이션 문제다. 직접 다해보면 된다. 




이사 중...


===============================================



하다가 멘탈 깨져서 정리함. 


서픽스 어레이의 n^2logn 풀이는 아주 간단하다. 소스 코드만 정리해보자면 ... 



1
2
3
4
5
6
7
8
9
10
vector<int> getSuffixArray(const string& s){
    vector<int> suffix; 
    //suffix배열을 초기화
    for (int i = 0; i < s.size(); ++i) suffix.push_back(i); 
    //문자열을 비교( 람다함수 사용 )
    sort(suffix.begin(), suffix.end(), [&s](int a, int b){
        return strcmp(s.c_str() + a, s.c_str() + b) < 0
    });
    return suffix; // 리턴
}
cs

 


아아아아아주 쉽다. 오히려 람다함수가 더 어려운듯...


방식자체는 설명하자면 n개의 문자열을 죄다 때려박은 후

(메모리를 적게 사용하기 위해서 인덱스만 때려박음 : 4번째 줄)


그 해당 문자열을 정렬한다. 근데 정렬하는데 드는 비용이 nlogn이고 하나의 문자열을 비교하는 비용이 n이므로 n^2logn이다. 

굉장히 못써먹을 시간복잡도라고 생각할 수 있지만 사실 문자열을 비교하는데 일반적인 경우, 항상 n이 걸리지는 않기 때문에 그럭저럭 쓸만하다.

... 인풋이 aaaaaaaaaaaaaaaaaaaa... 만 아니라면... 


이것보다 좋은 알고리즘으로는 맨버-마이어스의 알고리즘이 있다. 

이 알고리즘의 시간복잡도는 n * log n * log n  n을 로그로 떨군건데 

난 멍청해서 이걸 이해하는데 엄청 오래걸렸다.

내가 구글링을 잘 못하는 걸 수도 있는데 제대로 정리된 블로그가 없어... 그래서 정리함. 





 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
std::vector<int> getSuffixArray(const string& s) {
    int n = s.size();
    
    //idx + t 까지 비교한다!
    int t = 1
 
    //group[i]는 t까지 비교했을 때 i의 그룹 번호 
    vector<int> group(n + 1);
    //t==0일때를 대신한 거라고 봐도 무방... 
    for (int i = 0; i < n; ++i) group[i] = s[i];
    group[n] = -1;
 
    //서픽스를 담을 배열
    vector<int> suffix(n);
    //서픽스를 초기화
    for (int i = 0; i < n; ++i) suffix[i] = i;
 
 
    while (t < n) {
 
        //비교함수 아주 중요함
        auto cmp = [&group, t](int a, int b){
            if (group[a] != group[b])
                return group[a] < group[b];
            return group[a + t] < group[b + t];
        };
 
        //정렬
        std::sort(suffix.begin(), suffix.end(), cmp);
 
        t *= 2;
 
        //t가 n보다 크거나 같으면 종료
        if (t >= n) break;
 
        //그룹 재지정
        vector<int> newGroup(n + 1);
        newGroup[n] = -1;
        newGroup[suffix[0]] = 0;
        for (int i = 1; i < n; ++i){
            if (cmp(suffix[i - 1], suffix[i])){
                newGroup[suffix[i]] = newGroup[suffix[i - 1]] + 1;
             }else
                newGroup[suffix[i]] = newGroup[suffix[i - 1]];
        }
        group = newGroup;
    }
    return suffix;
}
cs

 



람다함수 [&group,t] <= group은 레퍼런스로 참조하고 t는 값을 복사해서 사용한다. 

나름대로 정리하자면 

s ? 구하려는 서픽스 배열의 target 스트링

group[i] ? i번째 접미사가 가지는 그룹 번호(index순) 

suffix[i] ? t까지 봤을때 i번째 접미사(사전 순)


t상태일때 어디까지 정렬되냐면 글자수가 2t일때까지 정렬된다.(즉 1일때는 글자수가 2개까지 정렬)

근데 이 그룹이라는 놈이 엄청나게 많은 것을 함축 하고 있는데 

group[a]는 사실 string의 [a...a+t)까지 비교한 결과의 상대 값이 저장되어 있다고 보면 된다.

이걸 이해하는데 이틀걸림. 


22~ 26줄의 compare함수를 보자. 


case : group[a] != group[b]

group[a]와 group[b]가 다를 때 group[a] < group[b]를 리턴한다. 

현재 t상태일때 벌써부터 group값이 다르다는 것은 이미 비교가 끝나있다는 것이다. 

그러니 a+t번째는 비교해볼 가치도 없음. 


case : group[a]와 group[b]가 같다.

string의 [a...a+t) [b...b+t)의 비교결과가 같다는 것이다. 

그럼이제 이걸 신경 쓸 필요가 없지.

[a+t...a+2t)와 [b+t...b+2t) 만 비교하면 된다. 

근데 이걸 일일이 다 비교하면 시간복잡도가 어마어마하게 증가한다. 

비교 할때마다 t만큼 추가 시간이 걸리니 말이다.

그리고 다행스럽게도 이 결과는 이미 저장되어 있다. 


어디에?

group[a+t]와 group[b+t]에!


그렇기 때문에 group[a+t]와 group[b+t]를 비교한 값을 리턴해주면 된다.


이 비교함수로 정렬이 완료되었으면 이제 이 결과를 다시 그룹에 반영해줘야 하는데 

이부분이 37~46줄이다. 

그룹의 값은 상대값이기 때문에 suffix의 첫번째 값은 0으로 설정하도록 하자. 

이제부터 suffix[n-1]까지 갱신해주는데 비교했는데 

이 비교의 기준은 이전 group과 t이다.(아직 갱신되기 전)

(실수로 t를 값이아니라 레퍼런스로 참조해봤는데 재밌는 일이 일어났다 ㅎㅎ)


case : suffix[i-1]과 suffix[i]를 비교

비교값이 더크데! <- 당연히 더 커야지 비교한 결과가... 

즉 이미 비교가 완료된 항목임.

그러니까 상대값도 1증가시켜줌. 

case : 현재까지 문자열을 사전순으로 비교할 수 없다. 

suffix배열은 t까지 진행했을때 정렬되어 있어야한다. 

즉 이부분은 아직 정렬이 제대로 이뤄지지 않았다는 것이고

따라서 아직까지는 suffix[i]와 suffix[i-1]은 누가더 사전순으로 우선인지 알 수 없다.

즉 suffix[i]와 suffix[i-1]은 길이가 2t일때까지 같았다는 것 

그룹번호를 같게 유지해서 다음 시퀀스에 비교할 수 있게 해두자.

(서픽스 어레이의 특성상 모든 문자열의 길이가 다르기때문에 같은건 존재할수없다.)


다른사람이 이해가 됐을지 모르겠다. 


내가 나중에 봤을때 이해할 수 있을 정도로만 정리해둔거라... 


틀린부분 있다면 지적부탁드려용.


참고 : 알고리즘 문제해결 전략 2권 suffix array파트 참조


p.s. suffix array관한 풀이는 최대 n까지 줄일 수 있고 이것보다 쉬운 nlogn풀이도 존재합니다.

p.s.2 그니까 저건 나중에 공부해서 포스팅할게요. 이거하는데도 지침 + sa와 한쌍인 lcp알고리즘도 다음에... 저가 너무 멍청해서


======================================================


이전 블로그에 있던 글 옮겨왔습니다. ㅎ 

'Problem Solving > 이론' 카테고리의 다른 글

nCr mod p 구하기  (2) 2018.04.26
거듭 제곱의 합  (2) 2016.10.22

거듭 제곱의 합 

 우리가 고등학교 수열과정에 배우는 내용중 하나인 거듭제곱 공식에 대해서 배운다.

 사실 많은 사람들이 이 공식에 관해서 머리속에 박아 외우고 있는 사람들은 많지만 정작 이런 공식들이 어떻게 나오는 지에 관해서는 모르는 경우가 많다.

 

1~n까지 모든 자연수들의 합을 나타내면

다음과 같이 표기한다. 보통 시그마라고 읽는다.  보통 우리들은 이 공식들을 외우고 있다.

 

혹시 이 공식의 증명법을 모르시는 분들을 위해서 한번 정리해 보자면 1)식과 2)식을 더하면 3)식이 나오는데 이때 (n+1)의 갯수가 총 n개 존재한다.(1~n이 n개존재하므로) 따라서 n(n+1)이된다.

그리고 그식을 정리하면 마지막 공식이 톡하고 튀어나오게 되시겠다.

 

이런 것들을 정리해 보자면

 

 

그런데 이게 4일때는? 5일때는? 6일때는?... k일때는?.... 

 

넘나 복잡한 것

 

이제 우리가 하고자 하는 일은 아래의 식을 모든 정수 k에대해 n에 관한 식으로 나타내는 것이다.

 

사실 여기서부터가 재밌다. 어떤 점화관계가 주어지면 재귀적으로 쉽게 풀 수 있는 문제들이 있다. 이는 재귀적으로 정의하고 그것을 정리하면 n에관한 식을 손쉽게 표현하고 구할 수 있을 것이다. 

 

우리는 문제를 풀기 앞서서 아래의 공식을 배운 적 있을 것이다.

위와 같은 식이 성립함으로 인해서 우리는 이 식을 가지고 장난을 쳐 우리가 원하는 바를 이루어 낼 것이다. 

(이 식을 처음 보시는 분들은 이항 정리에 관하여 검색해 보세요)

 

우리가 원하는 바를 이루기 위해서는 k+1에 관한 식이 필요하다. 그 이유는 포스트를 쭉 읽다보면 이해 할 수 있을 것이다. (k를 k+1로 치환하도록 하자)

 

이제 이 식에서 

을 좌항으로 옮길 것이다. 그렇다면 아래와 같은 식이 나타난다.

 

그리고 우리는 이식을 보면 하고 싶은 짓이있을 것이다. 계차수열의 일반항을 구할 때 했던 방법. 이제부터 x에 1부터 n까지의 수를 대입해보도록 하자.

 

 

이제우리가 할일은? 

 

다 더하기

 

그러면 좌측항이 아주 이쁘게 정리되면서 아래와 같은 식을 얻을 수 있다.

우리가 구하고 싶은 것은 S(n,k)이므로 이것에 대해 정리하기 위해서 S(n,k)만 우항에 놔두고 모든 식을 좌항으로 옮기도록 하자. 그렇다면

짜란 이제 우리는 임의의 k가 주어졌을때 S(n,0)~S(n,k-1)을 사용해 k일때의 n에 관한 식으로 만들 수 있다.

즉 점화식을 완성한 것이다 ^ㅇ^

 

 

 

식을 정리해서 만들었으니 k=2일때 제대로 정리 되었는지 보자.

 

 

 

 

 

완젼 잘나오네요 ㅎㅎ

k=3일때랑 k=4일때도 해보세요. 저는 귀찮아서 하기싫어여

 

사실 이 문제에 관해서 점화관계뿐만 아니라 일반항을 나타낼 수 있다. 베르누이 수를 이용해서라고... 

수학자가 아닌 내가 이해하기는 힘든 증명이라 링크만 달아 놓도록 하겠다. 

 

Faulhaber's formula

 

능력자 분들 중 이글을 보게 되는 분이 있다면 저것에 관해서 설명좀 부탁드려요..

 

이것과 관련된 알고리즘 문제 풀어보기

.

이걸 계산하는 프로그램을 원하시면 코멘트 달아주세요. 만들어 드리겠습니다.

 

 

 

참고

http://blog.naver.com/dalsapcho/20141141955

딱히 필요해서 정리하는 것은 아닌데 이런 것이 정리하고 공유하는게 다른 분들이 공부하기 더 쉬울 것 같아 포스팅 한다.


1. dovelet : www.dovelet.com

더블릿은 부분유료 사이트이다. 모든 문제를 볼수는 있다. 다만 1,2,3계단만 공짜로 채점 받을 수 있다. 즉 4단계 이상의 문제를 제출해 볼 수는 없다. 1,2,3단계는 기본적인 입출력, 반복문등을 연습하는 기초적인 단계이므로 알고리즘을 공부하기로 마음 먹은 사람에게 거의 필요없는 문제들이 많기 떄문에( 물론 코딩 속도를 올리는 용도로는 효과적이라는 이야기도 있다. ) 사실상 유료사이트라고 봐도 될 것 같다.


특징

장점

      1.  계단별로 특정 알고리즘의 설명, 수도코드, 소스코드등이 첨부되어 있어 혼자 공부하기 쉽다. 
      2. 특정 알고리즘을 배운 다음에 그 밑에 그 알고리즘으로 풀리는 문제들이 있다. 그 문제들을 풀어보며 감을 익힐 수 있다. 
      3.  만약 제출한 코드가 틀렸을 경우 틀린 testcase를 볼 수 있다. 

단점

      1.  제출한 코드가 틀렸을 경우에 틀린 testcase를 보여주는게 항상 좋은 것은 아니다.(실전 처럼 연습할 때 불편할 경우가 많다.)
      2.  테스트케이스가 빡빡하지 않다. 통과되지 말아야할 소스코드가 통과되는 경우가 왕왕 있었던 것으로 기억한다.
      3.  제대로 공부를 할 요량으로 이 사이트를 사용하려면 3만원? 정도되는 가격을 지불해야한다. (평생 사용 요금이다.)



2. 백준 온라인 저지 : www.acmicpc.net 

백준은 완전 무료사이트로 모든 문제를 공짜로 풀어볼 수 있다. 유아이도 상당히 이쁜 편이다. 직관적이고 상당히 많은 문제를 풀어 볼 수 있다. acmicpc관련 문제 + 올림피아드 관련 문제들이 많아 이 쪽 준비를 하는 사람들에게는 상당히 도움이 되는 사이트다. 질문 게시판들도 있어 모르는 문제를 물어볼 수 있다. 갓갓갓님들이 잘 답변해주신다고....



특징

장점

      1. 공짜다.
      2. 문제양이 상당히 많다.
      3. UI가 이쁘다.
      4. 갓갓갓님들이 주로 상주하는 사이트이고, 또 질문을 올릴 경우 이 갓갓갓 분들이 답변을 잘해주신다.
      5. 테스트 데이터가 빡빡한 편이라 어셉이 나지 말아야할 코드가 어셉이 나는 경우는 거의 없다. 있다고 해도 사람들이 찾아서 데이터를 보강해준다.  
      6. 그룹을 만들어 아는 사람들끼리 가상의 대회를 열어볼 수 있다.

단점

      1.  아직 분류 기능이 활성화 되어 있지 않아서 분류되어 있는 문제가 적다. 특정 알고리즘으로 푸는 문제를 분류탭에서 찾아보면 문제가 너무 적거나 말도안되게 어렵거나... 
      2. 친구기능이 없다. ㅠ

기타

      1. icpc.me/[문제번호] 라는 url로 접속하면 해당 문제로 바로 이동 가능하다.
         예) 자물쇠 문제 : icpc.me/1514
      2. BOJ 슬랙이 있다. 질문을 게시판으로 해도되지만 슬랙에 올려도 된다. 슬랙에 올리는 편이 더 자세한 답변을 들을 수 있는 것 같다.  



3. UVA, live archive: https://uva.onlinejudge.org/ ,https://icpcarchive.ecs.baylor.edu/

 되게 짜증나는 외국 사이트인데 처음 시작하는 사람에게는 별로 추천해주고 싶지는 않다. 문제양은 정말 많지만... 데이터 자체가 틀렸을 경우가 왕왕이아니라 아주 많다. (정답인 코드가 틀린다던가 하는) 뿐만아니라 개행문제등을 이유로 틀렸습니다가 뜨는 문제들이 너무많다.(스트레스... ) 


특징

장점

      1. 공짜다.
      2. 문제양이 상당히 많다.
      3. acmicpc관련 문제는 거의 대부분 있다.

단점

      1. 내가 알기로 문제 분류기능 따위는 없다. UI도 불편... 
      2. acm문제들 중 예선문제는 수록되어 있지 않다.
      3. acm문제들이 대부분 수록되어있으나 데이터가 틀린 경우가 너무 많다.
      4. 틀리기만 하는 것도아니고 데이터가 약한 것도 너무 많다.
      5. 개행등으로 틀렸습니다가 뜨는 경우가 많다.

기타

      1. 가상의 대회를 열어볼 수 있다. https://icpcarchive.ecs.baylor.edu/uhunt/
      2. 근데 위에 저게... 시간이나 문제링크등이 이상하게 되어있다. 짜증남... 


4. codeforces, topcoder : www.codeforces.com  , www.topcoder.com

 온라인 저지라기보다 컨테스트 사이트다. codeforces는 러시아 것이고 topcoder는 미국 것이다. 문제는 둘다 영어로 제공되며 게임처럼 레이팅을 경쟁할 수 있다. 레이팅별로 색깔이 달라지는데 빨간색, 노란색, 보라색 티어(?)가 있다. 롤로 치면 마스터, 다이아, 플레티넘 같은 것이라고 보면 된다. 레이팅 올리는 재미가 있으며 정규 컨테스트에서만 레이팅이 변경된다. 둘다 가상의 컨테스트를 열어볼 수 있고 DIV1/DIV2로 나누어져있는데 DIV1은 상위리그, DIV2는 하위리그다. 처음 시작 하는 분들은 DIV2 대회로 시작하시면 되겠다.

특징

장점

      1. 공짜다.
      2. 게임처럼 참가할 수 있다. 롤 레이팅 올리는 느낌이다. 
      3. 에디토리얼이라고 문제풀이가 제공된다. 따라서 보면서 공부할 수 있다.
      4. 둘다 핵 개념이 있는데 컨테스트중에 제공되는 테스트 케이스는 약한 테스트 케이스다. 따라서 어셉이나도 최종적으로 어셉이 아닐 수 있다. 이런 부분 때문에 각별히 예외나 시간복잡도 신경써야한다. 다른사람이 여러분의 소스코드를 읽고 틀린 데이터를 만들어 여러분의 소스코드를 공개할 수 있다.
      5. 반대로 문제를 잘 못풀어도 핵을 잘해서 점수를 딸 수 있다. 다른 사람의 소스코드에서 예외를 찾아 던지면 추가 점수를 얻을 수 있다.  

단점

      1.  소스코드를 읽기가 힘들다. 각종 define과 typedef의 연속... 
      2.  콘테스트에서 영어에 의해서 디버프를 받을 수 밖에 없다. 부족한 영어실력을 알고리즘 실력으로 극복해야한다. ㅠㅠ
      3.  핵당하면 괜히 기분이 나쁘다.
      4. 사이트가 빠른 편은 아니다. (아무래도 한 컨테스트당 몇천명의 사람이 몰리기 때문인 것 같다.) 




자세히 소개는 안했지만 다른  좋은 곳들도 많다. 

주로 사용하는 사이트만 리뷰하고 자주 사용하지 않은 사이트들은 정리하지 않았다. 잘못된 정보를 줄 수도 있기 때문에...

아래는 그외 사이트들이다.


알고스팟 : www.algospot.com 

수학관련 문제 - 프로젝트 오일러 :  http://projecteuler.net/ 

수학관련 문제 - 프로젝트 오일러(한국) : http://euler.synap.co.kr/ 

아주대학교 알고리즘 온라인 저지 라비다 : http://www.lavida.us/ 



원 출처 : 모름



문제 링크 : 

https://www.acmicpc.net/problem/1514


문제 설명 : 

 숫자로 이루어진 문자열 2개가 주어지는데 첫 번째 문자열을 두번 째 문자열로 바꾸는데 드는 최소 코스트를 구하는 문제.


 문자열에 가할 수 있는 연산은 최소 1개에서 최대 3개를 선택해서 그 값을 한꺼번에 최대 1이상 3이하 증가/감소 시킬 수 있다. 물론 숫자는 0~9까지만 사용하며 0밑으로 내려가면 9로, 9 이상으로 올라가면 0으로 다시 돌아간다. 즉 숫자를 회전시키는 것이라고 볼 수 있다.



dp 상태 정의 :


dy[n][t1][t2] :: 첫번째 부터 n번째까지 자물쇠를 돌렸을 때 n번째 숫자가 t2고 n-1번째 숫자가 t1이고 1~n-2까지의 숫자는 목표 다이얼을  완성한 상태 

t1과 t2는 0~9까지 값을 가진다.



전처리가 좀 필요한데 다른 분들은 수식만으로 구하신 것 같지만 나는 멍청함으로 수식따위 구하지 않고 직접 bfs를 사용해서 구했다.


 가장 기초적인 전처리 방법은  


 pre[s1][s2][s3][t1][t2][t3] :: 세 다이얼이 s1, s2, s3일 때 t1, t2, t3로 변환하기 위한 최소 코스트


 근데 이걸 전처리하기 너무 귀찮다. 일단 더럽게 배열이 6차원이다. 


이 전처리를 줄일 수 있는데 s1, s2, s3, t1, t2, t3 정보가 모두 필요하지 않다는 데 핵심 아이디어가 있다. 실제로 필요한 정보는 (t1 -s1), (t2 - s2), (t3- s3) 정보다. 따라서 전처리 해야하는 내용을  


 pre[s1][s2][s3]  원래 다이얼로 부터 차이 값이 s1, s2, s3일 때 변환하기 위한 최소 코스트 

로 정의 할 수 있다. 물론 구현의 편의상 (-1 == 9) (-2 == 8) ... 이다. 따라서 s1, s2, s3 는 모두 0에서부터 9사이의 값을 가진다. 


dp 점화식 :



여기서 

n2 == 원래 다이얼의 n번째 숫자 

t0 == 목표 다이얼의 n-2번째 숫자

cost((s0,s1,s2) ->(t0,t1,t2)) 는 pre[t0-s0][t1-s1][t2-s2]이다.


디피 테이블 하나를 체우는데 10^2이 들고 모든 테이블을 체우기 위해서는 n*10^2이 드므로 시간복잡도는 n* 10^4 




상당히 많이 틀렸던 문제. 


이문제를 처음 틀리고 나는 완벽한데 틀렸다며 부들부들했던 문제다.


실수할 여지가 좀 많다.

완전 알고리즘을 못하던 시절에 손댔다가 실패했던 문젠데 생각이 나서 풀고 해설을 써본다.(실제로 BOJ 자물쇠에 대한 풀이를 원하시는 분들이 많다고 들었다)


소스코드는... 더럽다. 알아서 읽어보세여 ^ㅇ^ (심지어 변수명도 다름)


소스보기


+ Recent posts