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

'Computer/Programming/Algorithm'에 해당되는 글 2건

  1. 2009/02/20 최대합 구하기 - (2)
  2. 2009/02/20 최대합 구하기

앞의 포스팅을 통해 "최대합 구하기"에 대한 내용을 언급한 바 있습니다. "생각하는 프로그래밍"은 각 컬럼의 마지막에 연습문제를 제시함으로써 정말 "생각"할 수 있는 기회를 주곤 하는데요, 해당 컬럼의 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 관련글 쓰기

댓글을 달아 주세요

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