Shinnara's Blog
Talking with Shinnara :: NaraTalk.com

'생각하는 프로그래밍'에 해당되는 글 3건

  1. 2009/02/20 최대합 구하기 - (2)
  2. 2009/02/20 최대합 구하기
  3. 2008/07/18 요즘 읽고 있는 책

앞의 포스팅을 통해 "최대합 구하기"에 대한 내용을 언급한 바 있습니다. "생각하는 프로그래밍"은 각 컬럼의 마지막에 연습문제를 제시함으로써 정말 "생각"할 수 있는 기회를 주곤 하는데요, 해당 컬럼의 10번 연습문제는 다음과 같습니다.

10. 최대합 대신에 0에 가장 가까운 합을 가지는 부분 벡터를 찾는 것이 목적이라 하자, 여러분이 이 문제를 풀기 위해 디자인 할 수 있는 가장 효육적인 알고리즘은 무엇인가? 어떤 알고리즘 디자인 기법을 적용할 수 있는가? 또 주어진 실수 t에 가장 가까운 합을 가지는 부분 벡터를 찾는다고 하면 어떻겠는가?


책을 읽는 목적이 좀더 효율적인 프로그래밍을 하고, 많은 생각을 하기 위함이라면, 이런 연습문제를 좀더 착실히(?) 풀어볼 필요가 있습니다. 실제로 도움도 많이 될테구요.

나이가 들어서인지 풀릴 듯 하면서도 잘 풀리지가 않았습니다. 가장 효율적인 알고리즘은 앞에서 이야기한 O(n)에 푸는 방법일테니까요.

고민을 하고 있다가, 잠시 차 한잔해야지 하고 밖에 나갔다가 불현듯 떠오르는 생각에 코드를 적어보니, 역시나 되더군요. 아직 많이 녹슬지는 않았나봅니다. ^^

먼저 부분합이 0에 가까워지는 케이스입니다.

min_abs(a,b)를 다음과 같이 정의해보기로 합니다.

int min_abs(int a, int b)
{
   if( abs(a) < abs(b) ) return a;
   else return b;
}


즉, 절대값이 작은 값을 반환하는 함수인데요, 예를 들어 -5 와 3을 입력하면 3이 나오고, -10 과 20을 입력하면 -10이 나오게 됩니다.

위와 같이 min_abs를 정의하고,

minendinghere = x[0]
minsofar = x[0]

for i=[1,n)
  minendinghere = min_abs(minendinghere + x[i], x[i])
  minsofar = min_abs( minsofar, minendinghere)


와 같이 적용하니 정확하게 0 에 가장 가까운 부분합을 표시하게 됩니다.

책에서 주어졌던 숫자 배열인

31, -41, 59, 26, -53, 58, 97, -93, -23, 84


에 대해서 적용해보면

Close to Zero : 4
From 6 To 7
97 -93


97과 -93을 더했을 때 4가 나오며 이 값이 0에 가장 가깝다는 것을 알 수 있습니다.

또한, 문제에서 임의의 실수 t에 가까운 부분합을 찾는 부분이 있는데, 이 역시 간단하게 적용이 가능합니다.
위에서 정의한 min_abs()를 아래와 같이 변경하는 것으로 구현이 가능합니다.

int min_abs(int a, int b)
{  
   if( abs(TARGET_NUMBER - a) <  abs( TARGET_NUMBER - b) ) return a;
   else return b;
}


즐거운 금요일이네요. 모두 행복하세요~

p.s. 연습문제를 더 살펴보니 13번에 다음과 같은 문제가 있네요.

13. 최대합 부분벡터를 찾는 문제에서 실수로 이루어진 n*n 배열이 주어졌고, 직사각형 모양의 부분 배열에 대한 최대합을 구해야 한다. 이 문제의 복잡성은 어느정도인가?

주말 동안 생각해볼 좋은 주제하나 얻었네요~





0 Trackback, 0 Comment

TRACKBACK :: http://naratalk.com/trackback/291 관련글 쓰기

댓글을 달아 주세요


 인사이트에서 번역 출간하여 개발자들에게 좋은 평가를 받고 있는 책인 "생각하는 프로그래밍"을 시간이 날 때마다 짬짬이 보고 있습니다. 주된 내용은 이미 학부때 배운 것들이지만, 10여년의 시간이 지난 지금 다시 읽어보면 감회가 새롭답니다. 덕분에 알고리즘 관련 책들을 다시 뒤적이게 됩니다.
 이 책에는 프로그래밍과 관련된 다양한 내용들이 나옵니다. 총 3부에 걸쳐 15개의 컬럼을 다루고 있는데요, 오늘 다룰 내용은 8번째에 소개되고 있는 "알고리즘 디자인 기법"입니다. 자세한 내용은 책을 참고하시기 바라며, 여기서는 해당 내용을 실제로 구현해보도록 하겠습니다.

풀고자 하는 문제는 다음과 같습니다.

"입력은 n개의 부동소수점 수로 이루어진 벡터 x이고, 출력은 입력된 벡터에 대한 연속적인 부분 벡터 각각의 합 중 최대값이다.(이를 최대합이라 한다)."


즉, 연속된 숫자의 합이 최대가 되는 부분을 찾는 문제입니다. 여기서는 문제를 간단히 하기 위해 정수만을 다루도록 합니다. 책에서는 모두 5가지의 알고리즘을 소개하고 있습니다. O(n^3) 에서부터 O(n)에 이르는 다양한 해법이지요. 자료구조(DS)나 알고리즘을 배우신 적이 있으시다면 O 표기법에 대해 잘 아시리라 믿습니다. 결론적으로 O(n)으로도 문제를 풀수 있고, 프로그램도 무척이나 간단합니다.

책에 나와 있는 코드는 아래와 같습니다.

maxsofar = 0
maxendinghere = 0

for i=[0,n)
  maxendinghere = max(maxendinghere + x[i], 0 )
  maxsofar = max( maxsofar, maxendinghere)


무척이나 간단하죠? 그리고 실제로도 너무나 잘 동작한답니다.  이를 C 코드로 바꾸는 것은 식은 죽 먹기보다 쉬울 것입니다.
그런데, 위의 코드는 단지 최대합만을 표시해줍니다. 어디서부터 어디까지를 더해서 나온 값이라는 부분이 없죠. 그래서 조금 바꾸어보았습니다.

   for(i=0;i<ARRAY_LENGTH;i++)
   {
      /*
      maxendinghere = max( maxendinghere + x[i], 0);
      maxsofar = max(maxsofar, maxendinghere);
      */
     
      if( maxendinghere + x[i] > 0 )
      {
         maxendinghere = maxendinghere  + x[i]; 
         end_here = i;
      } else
      {
         maxendinghere = 0;
         start_here = i+1;
      }
     
     
      if( maxsofar < maxendinghere )
      {
         maxsofar = maxendinghere;
         start_sofar = start_here;
         end_sofar = end_here;          
      }
     
   }

 
위의 코드에서 start_sofar, end_sorfar에 최대합을 이루는 부분의 시작과 끝 값이 들어가게 됩니다.

책에 보면 다음과 같은 10개의 연속값이 있습니다.

31, -41, 59, 26, -53, 58, 97, -93, -23, 84


이에 대해 위의 코드를 적용해서 수행해보면 아래와 같이 나오네요.

Max : 187
From 2 To 6
59 26 -53 58 97


배열 인덱스 2에서부터 6까지를 더하면 187이 나오며, 이 값은 책에 있는 값과 동일합니다.

프로그램을 테스트할 때 사용했던 값들을 좀더 표시해보면,

#define ARRAY_LENGTH 20

int x[ARRAY_LENGTH] = {

   -1,   9,  20, -50,  60,
   10,  23,   4, -10,   5,
   -2, -30,  15,  25,  80,
   65, -90, 150,  80,   4
};

에 대해

Max : 389
From 4 To 19
60 10 23 4 -10 5 -2 -30 15 25 80 65 -90 150 80 4


의 결과가 나옵니다.



0 Trackback, 0 Comment

TRACKBACK :: http://naratalk.com/trackback/290 관련글 쓰기

댓글을 달아 주세요

요즘 읽고 있는 책

책 읽는 즐거움 2008/07/18 13:20 by Shinnara
 오늘 쓰려고 하는 게 "책읽는  즐거움"이라는 분류에 어울릴만한 포스팅은 아닌데, 그래도 책 관련 이야기이니 분류를 그리 적어보았다. ( 본문의 책 이미지는 Yes24 에서 가져왔음을 알립니다.)

 1. Professional 소프트웨어 개발, 스티브 맥코넬 지음/ 윤준호, 한지윤 옮김 , 인사이트

사용자 삽입 이미지

 글쓴이는 "Code Complete", "Rapid Development", "소프트웨어 프로젝트 생존전략" 등의 저서로 유명한 스티브 맥코넬이다.  내 전공이 SE(Software Engineering)인지라 이런 종류의 책을 보면 궁금해서 견딜 수가 없다. 금전적 여유만 있다면 도서관이라도 차리고 싶은 마음이 굴뚝같다. 나도 MS의 누구처럼 개인 도서관을 꾸미는 것이 소원 중의 하나이다.
 이 책은 소프트웨어 개발에 대한 전반적인 내용을 다루고 있다. 아직 끝까지 읽지 않아서 총평을 내리기는 뭐하지만, 읽으면서 많은 것을 다시금 생각케한다. 앞으로 내가 어떠한 길을 갈것인지, 무엇을 더 준비하고 관심있게 보아야 하는지 등등...

업무 사이 사이에 한 챕터씩 읽곤 하는데, 꽤나 흥미롭다. 그리고 한 챕터가 끝날때마다 나오는 참고 문헌도 같이 읽는 다면, 꽤나 유용하리라 생각된다.

챕터는 철학자의 유명한 말과 함께 시작하는데, 가장 감동적이었던 것 하나만 소개해본다.

진실은 혼란보다 실수를 통해 더 빨리 다가올 것이다.
- 프란시스 베이컨


2. 생각하는 프로그래밍 , 존 벤틀리 지음/ 윤성준, 조상민 옮김 , 인사이트

사용자 삽입 이미지

아직 시작도 못하고 있음.. ^^














3. 프로그래밍 얼랭, 조 암스트롱 지음/ 김석준 옮김, 인사이트


사용자 삽입 이미지
  책을 소개하다보니 세 책의 출판사가 모두 "인사이트"인 기이한 현상. 물론 요즘 인사이트가 발간하는 책들이 대체로 좋은 이유도 있는 것 같다.

 '역자의 글'에도 나오듯이 '새로운 언어'를 배우는 것은 생각의 폭을 넓힐 수 있는 좋은 방법이다. 또한 '실용주의 프로그래머' 책에서도 1년에 한가지씩 새로운 언어를 배울 것을 권하고 있다. 현재 내가 잘 쓸 수 있다고 생각하는 언어는 기껏해야 Java 와 C. 하지만 이중에서 C는 그냥 업무상 활용하는 정도지 전문가라고 하기는 어려울 듯 하다. 접해본 언어를 모두 적으라면.... 초등학교 시절로 되돌아가서부터 Basic, Fortran 을 거쳐 Visual Basic , php, scheme, pascal, delphi 정도를 다루어 보았다. 최근에는 Ruby 와 Scala, Groovy 를 약간만 맛본 상태. Haskell 은 설치하고 샘플 프로그램만 돌려본 정도이다.

앞서 이야기 했듯이 올해부터라도 차근히 한해에 하나씩의 언어를 공부하고, 해당 언어의 중급이상의 실력을 갖추어보고자 한다. 그 시작은 얼랭(발음이 좀 이상하지만)으로 부터... ^^

Erlang 은 에릭슨에서 통신 교환기에 쓸 목적으로 만든 언어로서, Side-effect 가 없는 함수형 언어이다. 최근들어 멀티 코어 환경으로 빛을 발하고 있다는게 일반적인 평이다. 어제(2008-07-17)부터 읽기 시작했는데, 꽤나 흥미진진하다. 이 블로그에 Erlang 카테고리를 하나 추가해야 될 것같은 예감이....


0 Trackback, 0 Comment

TRACKBACK :: http://naratalk.com/trackback/250 관련글 쓰기

댓글을 달아 주세요

1 
다...... (264)
Computer/Programming (106)
Links (14)
책 읽는 즐거움 (7)
끄적임 (66)
즐거운 과학 나라 (7)
일본 (5)
Study (4)