[첫화면으로]Diary/오일러프로젝트300번문제

마지막으로 [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 (2010-09-15)[p]   | /오일러프로젝트300번문제 (2010-09-10) |   /2010-08-27 (2010-08-27)[n]   >>

Diary

최근 글들

코멘트와 트랙백

옛 글들

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

RSS

주요 페이지

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


마지막 편집일: 2012-2-11 12:25 am (변경사항 [d])
1451 hits | Permalink | 변경내역 보기 [h] | 페이지 소스 보기