[첫화면으로]Diary/2010-09

마지막으로 [b]

/오일러프로젝트300번문제

(해결되었습니다: /오일러프로젝트300번문제2)

도대체 제 풀이에 어디가 문제인지 몰라서 도움을 청하려고 작성합니다.

문제를 요약하면,
  • 단백질 패턴은 H또는 P원소로 구성됨 (예: HHPPHHHPHHPH)
  • 단백질은 H와 H가 서로 이웃하는 부분이 최대가 되도록 접히려는 성질이 있다.
    • 아래 그림은 HHPPHHHPHHPH 패턴의 경우. 좌측처럼 접히면 H-H의 갯수가 6개, 우측은 9개. 이 단백질의 경우는 9개가 최적
Upload:p_300_protein.gif
  • H와 P는 동일한 확률로 나온다고 가정
  • 문제: 최적의 상태로 접힌 길이 15인 단백질 패턴의 H-H 접촉지점의 갯수의 평균은?
    • 예제: 길이 8인 경우는 850 / 2^8 = 3.3203125

이런 문제에 익숙하다면 훨씬 빠르게 푸는 알고리즘을 생각할 수 있겠지만, 저는 일단 딱히 떠오르는 게 없어서 그냥
  • 길이 15개인 패턴이 접힐 수 있는 모든 형태를 미리 만들어두고
  • 2의 15승(=3만여)개의 패턴에 대해 각 형태에 대입하면서 H와H가 만나는 지점의 갯수를 세는
방법을 썼습니다.

처음에 작성했더니 길이가 8인 경우(문제에서 예제로 알려준)에 정답을 맞추더군요. 그래서 길이 15에 대해 풀라고 실행했더니... 오래 걸릴 거라 예상은 했지만 밖에 나가 밥을 먹고 돌아왔는데도 끝나지 않더군요. (아무래도 길이가 1 늘어날 때마다 가능한 조합이 기하급수적으로 늘어나니...)

그래서 여기저기 손보면서 불필요하고 무의미한 계산을 최대한 없앴습니다. 현재는 제 컴퓨터(애슬론 듀얼코어 5600+, 2.9GHz, Strawberry perl 5.10.0)에서 10분 걸리네요. 여전히 과하게 긴 감이 있습니다만...

문제는 시간도 시간이지만... 그렇게 10분에 걸쳐 풀었는데 답을 사이트에서 입력하면 틀렸다고 나옵니다. ㅠ,.ㅠ

처음에는 원인을 몰라서 끙끙댔습니다. 그러다가 혹시 나눗셈 계산하면서 결과가 반올림된게 아닌가 싶더군요. 그래서 나눗셈 하기 전 분자와 분모를 따로 출력했습니다:
  • 분모 (총합) = 264957
  • 분자 (2의 15승) = 32768
  • 분모/분자 = 8.085845947265625
  • 프로그램에서 출력할 때는 끝자리가 반올림되어서 8.08584594726563 으로 출력

이제는 맞았겠지 했는데... 저 값을 넣어도 여전히 안 됩니다 -_-?

저는 아무리 들여다봐도 "8자리일 때는 맞추는데 15자리일 때는 틀릴" 만한 구석을 못 찾겠습니다.

아래는 제 소스코드입니다. 코드패드 쪽에도 올려놨습니다. [여기]. 남의 코드 보는 게 아무래도 불편할터라 최대한 주석에 설명을 상세히 달아두었습니다만...

검증을 위해 길이 3부터 14까지의 실행결과도 적어두겠습니다.
제 프로그램의 실행결과.
길이 8의 경우를 제외하고 정확하다는 보장 없음
길이 15의 경우는 틀렸다고 나옴
 길이   총합 패턴갯수  평균
    3      4      8    0.5
    4     16     16    1.0
    5     46     32    1.4375
    6    133     64    2.078125
    7    335    128    2.6171875
    8    850    256    3.3203125
    9   1999    512    3.904296875
   10   4737   1024    4.6259765625
   11  10766   2048    5.2568359375
   12  24595   4096    6.004638671875
   13  54521   8192    6.6553955078125
   14 121601  16384    7.42193603515625
   15 264957  32768    8.085845947265625

-- Raymundo 2010-9-10 11:31 pm

Comments & Trackbacks

와 정말 도대체 어디가 문제인거지? 설마 그 사이트의 정답이 잘못 등록된 건 아닐테고... 90여명이 이미 풀었으니...
-- Raymundo 2010-9-11 9:59 pm

일단 문제만 보고, 생각만 정리 해봤네용...

1. 일단 이거 복잡도가 겁나큰 문제군요.
일단 숫자가 조금만 늘어도 사실상 P!=NP 문제가 되버리네요.
2. 특정 스트링패턴(DNA)이 가지는 모양은 한개 또는 다수입니다.(최대화)
근데 스트링패턴이 특정 모양에 겹쳤을때, '사실상' 중복되는 케이스는 없을까요?
(자세히 보진 않았지만 이게 좀.. 의심되네요)
3. 분산처리 해볼만한게 없을까요?(연산이 문제가 없다면 분산처리 해야겠네요)
저장 구조는 어떻게 가져가야 할까요? (전 비트맵 구조가 떠오르네요)
4. 어떻게 쓸데없는 녀석들을 초기에 커팅해 볼수 있을까요?

대략 ACM 3급수준 문제 되겠습니다. ~_~);
-- 죠짱 2010-9-14 1:01 am

최적화 이슈는
요거 보니까, 미리 패턴을 만들고, 최적 해를 먼저 계산이 가능하겠구요.
그걸 베이스로 하는거죠.
긍까 Raymundo님이 한 반대 방법으로 가보는거죠. 그럼 계산 최적화가 어느정도 되겠네요.

그리고 2^8을 생각한다고 해서 2^8이 될수도 있겠지만 환형을 생각하면 경우의 수가 줄어듭니다. 그말인 즉슨, asdf가 a-f가 만날경우 sdfa 랑 같다는 거죠. (동형, 동질) 요 케이스가 중복 패턴이라는 이야기구요. 아무래도 있을것 같군요. 그리고 아무리 짝수라도 asdf 일때 a만 따로 노는 경우가 없을까요? 있을거 같은데요. 그경우는 동형/동질의 패턴이 없겠군요.

그냥 자기전에 몇개 생각만 해봤습니다. 자러 가야지요
-- 죠짱 2010-9-14 1:16 am

일단 "패턴"이라는 말이 "어떻게 접혔느냐"와 "H와 P가 어떻게 조합되었느냐"에 둘 다 사용가능하니... 전자는 "형태", 후자를 "패턴"이라 칭하겠습니다.

제 풀이의 경우 "사실상 같은" 폴드 형태는 최대한 걸렀습니다.

- 형태를 90도씩 회전시킨 경우는 애초에 제외.
- 형태의 상하 또는 좌우대칭 형태도 생성 과정에서 제외.
- 각 길이별 형태을 다 만든 후에, 형태는 서로 다르지만 인접하는 이웃쌍이 동일한 경우를 제거 ([소스]의 55번라인 주석에서 처음 네 가지는 다 동일하죠)
- 그 외에 몇 가지 떠오르는 걸 시도해봤는데 그럼 아예 풀이에 오류가 생기길래 보류.

그리고 최적화 이슈의 경우...

저는
loop1: for ( 0 부터 2^n-1 까지의 모든 패턴에 대하여 )
loop2: for ( 생성해낸 형태 각각에 대입하면서 )
H-H CP 값 계산
을 하고 있는데,

문제 자체가 "모든 패턴에 대해 통틀어서 CP가 최대인 경우 얼마일까?" 이런 거라면 쉽겠는데 "각 패턴의 최대 CP값을 구해서 그 평균을 내라"다보니까, loop1 에서 반복 횟수를 줄이기가 힘들더군요. 그럼 loop2 에서 더 줄일 방법이 있나 봐야 하는데...

말씀하신대로 최적해를 (최적 형태를 의미하신 거 맞죠?) 먼저 구하려 해보았습니다. 그런데 이것도 생각처럼 쉽지 않았던게.. 최적 형태란 것도 결국 어느 패턴이 와서 대입되느냐에 따라 달라지겠더라고요.

예를 들어서
형태1:
0
1
2345
9876
형태2:
01
32
4
56789
위 두개의 경우 "최대로 생길 수 있는 CP의 갯수"는 형태1이 더 많습니다만, 패턴이 "111100000" 이라면 이 패턴은 형태2에서 CP값이 더 커지죠.

이걸, "그러면 환형처럼 생각해서 패턴을 쉬프트 시키면..."이라고 생각도 해봤는데, 쉽지도 않거니와 그 계산하느니 그냥 루프한번 더 도는 것과 비슷해보이기도 하고.

결정적으로, 저는 일단 계산 시간은 한시간이 걸려도 좋으니 정답부터 맞춰내보고 싶은데 답이 오류가 나고 있어서... =ㅅ=;;; 혹시 성공하시게 되면 답은 미리 말씀하지 마시고 제 실행 결과에서 길이가 몇일 때부터 틀렸는지 알려주시면 감사하겠습니다~ ^_^
-- Raymundo 2010-9-14 8:05 am

뭐래는 거얌..
-- Zehn02 2010-9-14 10:18 pm

으이구 악플러!
-- Raymundo 2010-9-14 10:33 pm
이름:  
Homepage:
내용:
 


주인장분류

/오일러프로젝트300번문제2

뭐가 문제였는지 깨달았습니다.

[제가 짠 코드]에서 256라인 쪽을 보면
        # 그런데 스트링의 뒷부분이 0으로 채워진 곳은 굳이 검사할 필요가 없다.
        # 예를 들어 001101110000000 패턴의 경우 마지막 PPPPPPP 는 어떻게 접히든 H-H의 갯수와 무관.
        # 따라서    00110111        패턴이라 생각하고 길이 8짜리 형태들과 비교하면 된다.

        my $t_length;       # 실제 검사할 길이 (마지막 "1"까지의 길이)
        if ( $str =~ /1(0*)$/ ) {
            $t_length = $length - length($1);
        }
라고 되어 있는데... 계산에 걸리는 시간을 줄이기 위해서 검사대상의 수를 줄이려는 방법 중의 하나였고, 실제로 꽤 시간절약을 할 수 있었습니다만...

이게 샘플로 주어진 길이 8까지는 적용할 수 있는데 길이가 9 이상이 되는 순간 함정이 나오더군요.

101010010 를 접을 경우, 끝의 0을 빼고 생각한다면 다음과 같이 접힙니다.
 65         00
074        111
123        010
* H-H가 만나는 지점은 세 곳
그러나 실제로는 저렇게 접힐 수가 없죠;;; 7다음 8번 원소가 붙을 자리가 남지 않으니까... 실제로는 다음과 같이
 65         00
874        011
 03         10
 12         01
* H-H가 만나는 지점은 두 곳
최적으로 접혀도 두 곳밖에 생기지 않습니다.

트위터에서 [aer0님]이 자기가 푼 것과 제가 푼 결과가 길이9에서부터 달라지며, 자신이 푼 값이 더 작더라..는 정보를 주셔서... 길이9에서 패턴을 일일이 찍다보니까 눈에 들어왔습니다.

지금 생각하면 '왜 저런 착각을 했을까' 싶을 정도로 간단한 이유인데...;; 위와 같이 그 뒤에 원소가 추가로 붙을 자리가 남지 않는 경우가 길이9에서 처음 나타나고, 저는 계속 손으로 검증할 수 있는 길이 6정도에서만 그려보다보니까 눈치를 못 채고 있었네요. (샘플로 길이8의 값을 준 이유가 이걸 노린 것 같기도...?)

한시간 전에 이 오류를 깨닫는 순간 벌떡 일어나며 컵에 남은 음료수를 들이키다가, 태어나서 가장 심하게 사레가 들렸습니다. 익사할 때 심정을 조금은 느꼈는지도 -_-;;; 지금도 가슴이 얼얼하군요...
-- Raymundo 2010-9-15 1:48 am

Comments & Trackbacks

신난게 눈에 보여.. 새벽에 눈도 못뜬 상태에서 다 풀었다고 하면서, 의기양양했음.
-- Zehn02 2010-9-15 8:54 am
이름:  
Homepage:
내용:
 


주인장분류

/주차장싸이렌

자려고 누웠다가 싸이렌 소리에 자꾸 신경이 쓰여서 잠을 설친 김에... -_-;

고향 떠나 타지 생활 하다가 처음으로 아파트에도 살아보고, 이후 이사 몇 번 하면서 지금 사는 곳까지 네 번째 아파트인데... 첫 단지는 제가 차가 없어서 관심이 없어서 모르겠고, 두번째 단지는 아예 지하주차장이 없었고, 세번째는 있긴 했는데 싸이렌 같은 거 전혀 없었고, 이번에 처음으로 지하주차장의 층간 경사로 양 끝에 싸이렌이 달려 있더군요.

처음에야 신기했고 사고 예방을 위해서 필요하다고 생각은 하는데, 이게 하루이틀 갈수록 완전 소음덩어리...

제일 궁금했던 건 이거였습니다. 차가 경사로를 올라가는 것과 내려가는 것을 어떻게 구분하여 인식하는 걸까였는데...

어느 날 다른 차가 들어가는 걸 봤더니만 그런 구분 안 하더군요 -_-; 그 차가 지상에서 주차장 입구로 접어드는 순간에는 그 경사로의 지하1층 쪽 싸이렌이 울리고, 그 차가 지하1층 도착해서 경사로를 빠져나가는 순간 지상 쪽 싸이렌이 울리더라고요. 자기가 운전 중일 때는 눈앞의 싸이렌만 보이고 창문을 닫아두니 뒤에서도 울리고 있는 줄은 몰랐죠.

아침에야 주차장에서 차가 나오는 거니까 어쩔 수 없다 치고... 저녁 이후에는 아무래도 주차장에 들어가는 차들이 대부분인데, 그때마다 지상에 있는 싸이렌이 불필요하게 괴성을 질러댑니다. 그리고 지금처럼 한밤중에도...

그나마 저희 집은 십수층에 있지만 그 싸이렌 코앞에 있는 가구들은 참 참기 힘들겠다 싶은데 말이죠.
-- Raymundo 2010-9-18 1:16 am

Comments & Trackbacks
이름:  
Homepage:
내용:
 


주인장분류

/2010년추석

아무리 요새 트위터에 다 써서 일기를 안 쓰는 추세지만... 기록 차원에서,
  • 내려간 다음날 서울은 비 폭탄
  • 직전 토요일날 배송받은 Iphone 들고 갔는데 와이파이 없는 곳만 찾아다니느라 계속 3G로 인터넷 했다가 3일만에 160MB 쓰고 월말까지 긴축재정 상황 -_-; (월 중간에 가입했기 때문에 이번 달 말까지 사용 가능한 용량은 210MB)
  • 항암치료 중인 어머니는 명절 스트레스를 받으셨는지 내내 기력이 없고 식사를 제대로 못하셔서 안타까웠음. 다행히 올라올 무렵에는 괜찮아 지신 듯 한데...
  • 그나마 추석은 작은집에서 치르기 때문에 부담이 덜해서 다행이다. 매년 설과 할아버님 제사는 우리집에서, 추석과 할머님 제사는 작은집에서 하는데, 이렇게 나눠지내는 것이 얼마나 좋은지는 즐겨가는 모 커뮤니티 사이트 등에서 종종 올라오는 장손들의 하소연 글 읽으면서 체감한다.
  • 서울 도착하니 정말 비가 그리 왔던 게 맞나 싶을 정도로 화창했다.
Upload:20100926.jpg

-- Raymundo 2010-9-26 11:39 pm

Comments & Trackbacks
이름:  
Homepage:
내용:
 


주인장분류


주인장분류
<<<   Diary/2010-10 [p]   | 월별 보기 |   Diary/2010-08 [n]   >>>

Diary

최근 글들

코멘트와 트랙백

옛 글들

  • /Archive - 월별로 한번에 보기
  • /List - 전체 포스트 목록

RSS

주요 페이지

이 홈페이지의 인터위키는 다음과 같습니다.
GyparkWiki  UTF-8
https://gypark.pe.kr/wiki/


마지막 편집일: 2011-7-8 1:13 pm (변경사항 [d])
546 hits | Permalink | 변경내역 보기 [h] | 페이지 소스 보기