알고리즘과 데이터 구조 그리고 패턴

디자인패턴로그 2011. 8. 16. 22:51




디자인 패턴의 카테고리는 크게 생성, 행동, 구조 이렇게 3가지로 분류된다. 왜 이렇게 3가지로 분류될까?
 
경험이 많지는 않지만 내 생각에는 소프트웨어 개발에 있어서 빠질래야 빠질 수 없는 가장 큰 범주의 패턴이 
바로 이 3가지 이기 때문이다. 컴퓨터 공학에서 "알고리즘과 데이터 구조" 는 굉장히 중요한 분야이다.  프로그래밍의
근본을 이루는 분야이기 때문에 대학 및 실무에서도 "알고리즘과 데이터 구조" 에 대한 기초를 중요시 여긴다. 
데이터를 어떠한 형태로 구성하는냐 그리고 어떠한 처리방법을 선택하느냐 에 따라 프로그램에 유지보수성과 성능이
좌지우지 되기 때문일 것이다. 객체지향 패러다임으로 관점을 옮겼을 때 그대로 맵핑된 것이다. "행동" 과 "구조" 패턴이다. 
클래스를 사용하는 객체지향의 문맥에 맞게 표현된 단어이지만 근본적으로 각각 알고리즘과 데이터 구조를 표현하는 말이다. 

알고리즘을 캡슐화하여 어떻게 유연하게 알고리즘에 변경을 적용할 수 있을까에 대한 고민이 "행동" 카테고리의 패턴들이다.
클래스들(객체들) 간에 어떻게 구조를 형성하여 특정 요구사항에 유용한 구조를 얻을 수 있을까에 대한 고민이 "구조"  카테고리의 패턴들이다. 



이에 더하여 프로그램에서 빠질 수 없는 것이 (변수 또는 객체에 대한) 생성이다. 일단 생성이 되어야 "행동"과 "구조"를 적용할
수 있지 않겠는가?

클래스(객체)들을  생성하는 방식을 어떻게 캡슐화하여 유연성을 얻을까에 대한 고민이 "생성" 카테고리의 패턴들이다. 



이러한 이유들로 인해서 여러 패턴들이 3가지 카테고리로 분류되어 있다. 이점을 염두해 두고 패턴들을 생각하면 좀더 쉽게 이해가 될 것이다. 사내 스터디 교재로 Head First Design Pattern을 택했기 때문에 여기에서 등장하는 패턴순으로 설명해나갈 것이며
패턴을 설명하기 위한 예제는 될수 있으면 실제로 사용하고 적용했던 코드를 사용할 것이다. 
 
이 책에서 소개하는 패턴들의 순서는 다음과 같다. 

디자인 패턴 소개
옵저버 패턴
데코레이터 패턴
팩토리 패턴
싱글턴 패턴
커맨드 패턴
어댑터 패턴과 퍼사드 패턴
템플릿 메소드 패턴
이터레이터와 컴포짓 패턴
스테이트 패턴
프록시 패턴
컴파운드 패턴
...


 


'디자인패턴로그' 카테고리의 다른 글

객체지향의 원칙  (0) 2011.08.17
알고리즘과 데이터 구조 그리고 패턴  (0) 2011.08.16
디자인 패턴에 대한 고찰  (0) 2011.08.16

원 위에 나열된 수 제거하기

알고리즘.데이터구조 2011. 3. 23. 16:08





1부터 n까지의 수를 원 위에 차례로 나열하고 k 번째 수를 지워간다.  k보다 적을 때까지 반복한다

입력: n, k (n > k > 0)

출력: 최종 남은 숫자들(지워진 순서로 출력, 역순으로 출력) / 지워진 숫자들

조건: 함수는 재귀적인 기법 이용  / n보다 적은 배열 하나만 이용



1. 반복루프를 사용한 방법
(1) n크기의 배열을 사용. 어떤 수 n은 (n-1)배열요소에 위치한다
(2) K번째 배열요소에는 지워진 순서가 기록되고, 남아있는 수의 배열요소에는 0값을 저장하고 있다.
(3) 함수 종료 후, 기록된 순서를 통해 지워진 순서, 역순 출력을 할수 있고,
      배열요소가 0인 것을 찾아 남아있는 수들을 출력 할 수 있다.







2. 재귀함수를 사용한 방법
(1) 단순히 위의 반복버전을 재귀함수로 변경한 버전







3. 최고 n - (n/k) 크기의 배열을 사용하는 재귀함수
(1) 첫번째, 두번째 재귀호출은 배열을 한번 순회하기 위해 루프문을 구현한 것이고,
(2) 세번째 재귀호출은 한번의 순회의 남아있는 수들로 재구성한 새 배열을 가지고, (1)과정을 재적용한다.
(3) 알고리즘이 종료하면 전역변소 $e에는 남아있는 수의 개수를 저장하고 있으면 array의 0~($e-1) 요소에 그 값이 위치한다




3번에 대한 그림 설명




'알고리즘.데이터구조' 카테고리의 다른 글

[알고리즘] 알고리즘 글 목록  (0) 2013.07.08
프로그래밍 문제 접근법  (0) 2011.04.26
원 위에 나열된 수 제거하기  (0) 2011.03.23
합병정렬(Merge Sort)  (0) 2011.03.23
HMAC-SHA1  (0) 2011.03.11
문제5 그래픽편집기  (0) 2011.02.18

합병정렬(Merge Sort)

알고리즘.데이터구조 2011. 3. 23. 15:50



 n개의 아이템으로 구성된 리스트를 크기가 거의 n/3 인 3개의 부분리스트로 분할하고
각 부분리스트를 재귀적으로 정렬한 후, 그 3개의 정렬된 부분리스트를 합병하는 정렬 알고리즘을 작성하라 (n>=100)

 => 합병정렬(merge sort) 알고리즘을 작성하되, 3분할 방식을 사용하라~~는 말


먼저 2분할을 사용하는 합병정렬 소스는 다음과 같다








3분할을 사용하는 MergeSort (Ruby 버전)
# 배열리스트를 n/3으로 분할 후 정렬 / 병합
def merge_sort(low, high)
	if (high-low >= 2)
		mid1 = (high-low) /3 + low
		mid2 = ((high-low)*2)/3 + low
		
		merge_sort(low, mid1)
		merge_sort(mid1+1, mid2)
		merge_sort(mid2+1, high)
		merge(low, mid1, mid2, high)
	else
		if (high-low==1 && $a[low] > $a[high])
			tmp = $a[low]
			$a[low] = $a[high]
			$a[high] = tmp
		end
	end
end

def merge(low, mid1, mid2, high)
	i, h, j, m, k = low, low, mid1+1, mid2+1, 0	

	b = []
	pass = false;
	while ((h<=mid1) and (j<=mid2) and (m<=high))
		if ($a[h] <= $a[j] && $a[h] <= $a[m])
			b[i] = $a[h]
			h = h + 1
			i = i + 1
			next	
		end	
		if ($a[j] <= $a[h] && $a[j] <= $a[m])
			b[i] = $a[j]
			j = j + 1
			i = i + 1
			next	
		end
		if ($a[m] <= $a[h] && $a[m] <= $a[j])
			b[i] = $a[m]
			m = m + 1
			i = i + 1
			next	
		end
	end
	# 루프가 종료하고 남은 요소들을 병합
	if (h > mid1 && !pass)
		pass = true
		while ((j<=mid2) and (m<=high))
			if ($a[j] <= $a[m])
				b[i] = $a[j]
				j = j + 1
			else
				b[i] = $a[m]
				m = m + 1
			end
			i = i + 1
		end
		if (j > mid2)
			for k in m..high
				b[i] = $a[k]
				i = i + 1
			end
		else
			for k in j..mid2
				b[i] = $a[k]
				i = i + 1
			end
		end
	end
	if (j > mid2 && !pass)
		pass = true
		while ((h<=mid1) and (m<=high))
			if ($a[h] <= $a[m])
				b[i] = $a[h]
				h = h + 1
			else
				b[i] = $a[m]
				m = m + 1
			end
			i = i + 1
		end
		if h > mid1
			for k in m..high
				b[i] = $a[k]
				i = i + 1
			end
		else
			for k in h..mid1
				b[i] = $a[k]
				i = i + 1
			end
		end
	end
	if (m > high && !pass)
		while ((h<=mid1) and (j<=mid2))
			if ($a[h] <= $a[j])
				b[i] = $a[h]
				h = h + 1
			else
				b[i] = $a[j]
				j = j + 1
			end
			i = i + 1
		end
		if (h > mid1)
			for k in j..mid2
				b[i] = $a[k]
				i = i + 1
			end
		else
			for k in h..mid1
				b[i] = $a[k]
				i = i + 1
			end
		end
	end
    # 원배열에 정련된 임시배열값을 복사	
	for k in low..high
		$a[k] = b[k]
	end
end

#$a = [1,5,4,3,2,6,9,7,8]
$a = Array.new(100)
$a.each_index { |i| $a[i] = rand(100)+1 }

$a.each { |x| print x, " " }
merge_sort(0,99) 

print "결과\n"
$a.each { |x| print x, " " }









3분할을 사용하는 MergeSort (C++ 버전)
#include <iostream>

using namespace std;

void mergeSort(int * a, int low, int high);
void merge(int * a, int low, int mid1, int mid2, int high);
void print(int * arr, int size);
int * minThree(int * a, int *i, int *j, int *k);
int * minTwo(int * a, int *i, int *j);


int main()
{
	int size = 100;
	int * arr = new int[size];

	srand(time(NULL));
	// 초기화- 0~99까지 수를 랜덤으로 복사
	for (int i=0; i < size; i++)
		arr[i] = rand() % size;

	// 정렬 전 
	print(arr, size);

	mergeSort(arr, 0, size-1);
	// 정렬 후 
	print(arr,size);

	return 0;
}


void mergeSort(int * a, int low, int high)
{
	int mid1, mid2;

	if (high-low >= 2)
	{
		mid1 = (high-low)/3 + low;
		mid2 = ((high-low)*2)/3 + low;

		mergeSort(a, low, mid1);
		mergeSort(a, mid1+1, mid2);
		mergeSort(a, mid2+1, high);
		merge(a, low, mid1, mid2, high);
	}
	else
	{	
		if (high-low==1 && a[low] > a[high])
		{
			int tmp = a[low];
			a[low] = a[high];
			a[high] = tmp;
		}
	}
}


void merge(int * a, int low, int mid1, int mid2, int high)
{
	int * b = new int[high-low+1];
	bool pass = false;  // 조건을 만족할 경우 나머지 if문을 통과하기 위한 변수
	int i, h, j, m;
	
	i = 0;
	h = low;
	j = mid1 + 1; 
	m = mid2 + 1;

	// 세분할 배열중 하나를 다 복사할때까지 루프를 돈다
	for (; h<=mid1 && j<=mid2 && m<=high; i++)
	{
		int * p = minThree(a, &h, &j, &m);
		b[i] = a[*p];
		*p = *p + 1;
	}

	if (h > mid1)
	{
		pass = true;
		// 나머지 두 분할 배열중 하나를 다 복사할때까지 루프를 돈다
		for (; j<=mid2 && m<=high; i++)
		{
			int * p = minTwo(a, &j, &m);
			b[i] = a[*p];
			*p = *p + 1;
		}
		// 나머지 하나의 분할배열을 복사한다
		if (j > mid2)
			for (; m<=high; i++, m++)
				b[i] = a[m];
		else
			for (; j<=mid2; i++, j++)
				b[i] = a[j];
	}

	if (j > mid2 && !pass)
	{
		pass = true;
		for (; h<=mid1 && m<=high; i++)
		{
			int * p = minTwo(a, &h, &m);
			b[i] = a[*p];
			*p = *p + 1;
		}

		if (h > mid1)
			for (; m<=high; i++, m++)
				b[i] = a[m];
		else
			for (; h<=mid1; i++, h++)
				b[i] = a[h];
	}

	if (m > high && !pass)
	{
		for (; h<=mid1 && j<=mid2; i++)
		{
			int * p = minTwo(a, &h, &j);
			b[i] = a[*p];
			*p = *p + 1;
		}

		if (j > mid2)
			for (; h<=mid1; i++, h++)
				b[i] = a[h];
		else
			for (; j<=mid2; i++, j++)
				b[i] = a[j];
	}

	// 정렬된 임시배열을 원본배열에 복사한다
	for (int k=low; k <= high; k++)
		a[k] = b[k-low];
	
}

// 배열의 내용 출력
void print(int * a, int size)
{
	for (int i=0; i < size; i++)
		cout << a[i] << " " ;	
	cout << endl;

}


// 세 분할배열에 숫자 중 가장 작은수의 인덱스를 반환
int * minThree(int * a, int *i, int *j, int *k)
{
	if (a[*i]<=a[*j] && a[*i]<=a[*k])
		return i;
	if (a[*j]<=a[*i] && a[*j]<=a[*k])
		return j;
	if (a[*k]<=a[*i] && a[*k]<=a[*j])
		return k;
}

// 두 분할배열에 숫자 중 가장 작은수의 인덱스를 반환
int * minTwo(int * a, int * i, int * j)
{
	if (a[*i]<=a[*j])
		return i;
	else
		return j;
}	






'알고리즘.데이터구조' 카테고리의 다른 글

프로그래밍 문제 접근법  (0) 2011.04.26
원 위에 나열된 수 제거하기  (0) 2011.03.23
합병정렬(Merge Sort)  (0) 2011.03.23
HMAC-SHA1  (0) 2011.03.11
문제5 그래픽편집기  (0) 2011.02.18
문제4 LCD디스플레이  (0) 2011.02.18

HMAC-SHA1

알고리즘.데이터구조 2011. 3. 11. 00:36


 

 

HMAC

송신자와 수신자가 비밀 키를 공유할 경우 서로 주고받은 메시지의 훼손여부를 확인하는데 사용하는 메시지 인증방식이다.

송신자가 원데이터의 해시값을 계산하여 원데이터와 해시값 모두 단일 메시지로 보내면, 수신자가 받은 메시지에 대해 

해시값을 다시 계산하여 계산된 HMAC과  전송된  HMAC의 일치여부를 확인한다. 


 

SHA-1(Secure Hash Algorithm)

미국 정부에서 공개한 암호화 해시 알고리즘으로, 임의 길이의 문자열에서 160비트 해시값을 생성을 생성한다. 

 SHS 및 Secure Hash Standard라고도 한다.



HMAC-SHA1

SHA1 해시함수를 사용하여,  HMAC 을 구현하는 키 지정 해시 알고리즘이다. 다음과 같은 HMAC 프로세스를 따른다.  

1) 비밀 키를 메시지 데이터와 혼합한다

2) 해시 함수를 통해 결과를 해시한다

3) 해시값을 비밀키와 다시 혼합한다 

4) 그런 다음 해시함수를 다시 적용한다 




'알고리즘.데이터구조' 카테고리의 다른 글

원 위에 나열된 수 제거하기  (0) 2011.03.23
합병정렬(Merge Sort)  (0) 2011.03.23
HMAC-SHA1  (0) 2011.03.11
문제5 그래픽편집기  (0) 2011.02.18
문제4 LCD디스플레이  (0) 2011.02.18
문제3 여행  (0) 2011.02.18

문제5 그래픽편집기

알고리즘.데이터구조 2011. 2. 18. 11:41


이미지를 M X N 배열로 표현하는 간단한 대화형 그래픽 편집기  프로그램을 만들어보자.

 

 입력

한 줄에 하나씩의 1개 문자의 명령으로 구성됨.  매개변수는 스페이스로 분리됨 

픽셀좌표는 1 이상 M이하의 열, 1이상 N이하의 행 으로 표현됨. 

표의 왼쪽 위 꼭지점이 원점이며, 색은 대문자로 지정함 

 

 

출력

명령을 제외한 문자는 무시하고,  S Name 명령은 Name 으로 주어진 파일명 출력 후

현재 이미지 내용을 출력함.

 

I M N   M X N 이미지를 새로 생성 후, 흰색(O)으로 초기화
C  모든 픽셀을 흰색으로 칠한다
L X Y C  (X, Y) 픽셀을 주어진 색(C)로 칠한다
V X Y1 Y2 C  X열에 Y1행과 Y2행 (Y1, Y2포함)사이에 색(C)으로 수직방향 직선을 그린다 
H X1 X2 Y C  Y행에 X1열과 X2행(X1, X2포함)사이에 색(C)으로 수평방향 직선을 그린다
K X1 Y1 X2 Y2 C  주어진 색(C)로 채워진 직사각형을 그리되, X1 Y1은 왼쪽 위끝점 X2 Y2는 오른쪽 아래 끝점
F X Y C  R영역을 색 C로 채운다. R 영역은 X Y 점이 포함되고, 해당 점과 상 하 좌 우  이웃하는 점이 R영역으로 포함된다.
S Name  파일명을 입력받은 대로 출력 후, 현재 이미지 내용을 출력한다.
X  프로그램 종료 


 



graphic_editor.c


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_SIZE 100

typedef struct _Image {
	char *pixels;
	int r, c;
} Image;

typedef struct _Point {
	int x, y;
} Point;


Point make_point(int x, int y);

 
Image* initiate(int row, int col);
void fill_color(Image *image, Point point, char color);
void show(Image *image);
void flood(Image *image, Point point, char color);
void flood_recur(Image *image, Point point, char color, char r_color); 
void horizontal_line(Image *image, int x, int y1, int y2, char color);
void vertical_line(Image *image, int x1, int x2, int y, char color);
void rectangle(Image *image, Point left_top, Point right_bottom, char color);
void clear(Image *image, char color);


int main (int argc, char const* argv[])
{
	char cmd, color;
	char buf[MAX_SIZE], name[MAX_SIZE];
	int m, n, x1, x2, y1, y2;
	Image *image = 0;

	while (fgets(buf, 100, stdin) != NULL && strncmp(buf, "X", 1) != 0) {
	 	if (strncmp(buf, "I ", 2) == 0) {
		
			sscanf(buf, "%c %d %d", &cmd, &m, &n);
			image = initiate(n, m);
			
		} else if (strncmp(buf, "C", 1) == 0) {\
	
			clear(image, '0');
			
		} else if (strncmp(buf, "L ", 2) == 0) {
			
			sscanf(buf, "%c %d %d %c", &cmd, &x1, &y1, &color);
			fill_color(image, make_point(x1-1, y1-1), color);	
			
		} else if (strncmp(buf, "V ", 2) == 0) {
			
			sscanf(buf, "%c %d %d %d %c", &cmd, &x1, &y1, &y2, &color);
			vertical_line(image, x1-1, y1-1, y2-1, color);
			
		} else if (strncmp(buf, "H ", 2) == 0) {
			
			sscanf(buf, "%c %d %d %d %c", &cmd, &x1, &x2, &y1, &color);
			horizontal_line(image, x1-1, x2-1, y1-1, color);
			
		} else if (strncmp(buf, "K ", 2) == 0) {
			
			sscanf(buf, "%c %d %d %d %d %c", &cmd, &x1, &y1, &x2, &y2, &color);
			rectangle(image, make_point(x1-1, y1-1), make_point(x2-1, y2-1), color);
			
		} else if (strncmp(buf, "F ", 2) == 0) {
		
			sscanf(buf, "%c %d %d %c", &cmd, &x1, &y1, &color);
			flood(image, make_point(x1-1, y1-1), color);
			
		} else if (strncmp(buf, "S ", 2) == 0) {
			
			sscanf(buf, "%c %s", &cmd, name);
			printf("%s \n", name);
			show(image);
		}
	}
	
	return 0;
}

Point make_point(int x, int y) {
	return (Point){x, y};
}



// 이미지 생성 - I m n 
Image* initiate(int row, int col) {
	Image *image = (Image*)malloc(sizeof(Image));
	
	image->pixels = (char*)malloc(row*col); 
	image->r = row;
	image->c = col;
	
	clear(image, '0');
	
	return image;
}

// 주어진 픽셀에 칠하기 - L x y c
void fill_color(Image *image, Point point, char color) {
	image->pixels[point.y*image->c +  point.x] = color;
}

// 이미지 출력 
void show(Image *image) {
	int i;
	
	for (i = 0; i < image->r * image->c; i++) {
		putchar(image->pixels[i]);
		
		if (i % image->c == image->c - 1) {
			putchar('\n');
		}
	}
}

// 점람 채우기 
void flood(Image *image, Point point, char color) {
	char r_color = image->pixels[point.y*image->c +  point.x];
	flood_recur(image, point, color, r_color);
}


void flood_recur(Image *image, Point point, char color, char r_color) {
	int x = point.x;
	int y = point.y;
	int index = y*image->c + x;
	
	// 경계를 벗어났거나 같은 영역이 아니면 종료 
	if (image->pixels[index] != r_color || x < 0 || y < 0 || x >= image->c || y >= image->r) {
		return;
	}
	image->pixels[index] = color;
	
	flood_recur(image, make_point(x, y+1), color, r_color);
	flood_recur(image, make_point(x+1, y), color, r_color);
	flood_recur(image, make_point(x, y-1), color, r_color);
	flood_recur(image, make_point(x-1, y), color, r_color);
}


// 수평 직선  - H
void vertical_line(Image *image, int x, int y1, int y2, char color) {
	Point left_top, right_bottom;
	
	left_top.x = right_bottom.x = x;
	left_top.y = y1;
	right_bottom.y = y2;
	
	rectangle(image, left_top, right_bottom, color);
}


// 수직 직선  - V
void horizontal_line(Image *image, int x1, int x2, int y, char color) {
	Point left_top, right_bottom;
	
	left_top.x = x1;
	right_bottom.x = x2;
	left_top.y = right_bottom.y = y;
	
	rectangle(image, left_top, right_bottom, color);
}

// 사각형 그리고 채우기 - K
void rectangle(Image *image, Point left_top, Point right_bottom, char color) {
	int i, j;
	
	for (i = left_top.y; i <= right_bottom.y; i++) {
		for (j = left_top.x; j <= right_bottom.x; j++) {
			image->pixels[i*image->c + j] = color;
		}
	}
}


void clear(Image *image, char color) {
	int i;
	for (i = 0; i < image->r * image->c; i++) {
		image->pixels[i] = color;
	}
}



'알고리즘.데이터구조' 카테고리의 다른 글

합병정렬(Merge Sort)  (0) 2011.03.23
HMAC-SHA1  (0) 2011.03.11
문제5 그래픽편집기  (0) 2011.02.18
문제4 LCD디스플레이  (0) 2011.02.18
문제3 여행  (0) 2011.02.18
문제2 지뢰찾기  (0) 2011.02.18

문제4 LCD디스플레이

알고리즘.데이터구조 2011. 2. 18. 11:40


 

LCD 디스플레이 형태로 숫자를 출력하되 크기 입력 s에 의해 출력하는 숫자의 크기를 조절할 수 있다.

이 때 각 숫자는 s+2개의 열과  2s+3 개의 행 크기를 차지하게  된다. 행문자는 ' | ',  열 ' -' 를 사용. 

각 자리 수 사이에는 1칸씩 공백을 둔다. 


입력 : s n  (크기 s, 출력할 정수 n)

출력 :  LCD 디스플레이 형태로 n을 출력 

 

 

문제해결

두 가지 방법으로 해결법을 찾아 보았다. 첫번째는 0 ~ 9 까지 각 수를 인자 s에 따라 출력하는 

일반적인 방법이다. 두번 째는 LCD 패널을 7가지 구성요소로 분리하고, 각 요소를 7개의 함수로 

만들고, 0~9중 해당하는 수가 입력된 경우에만 해당 요소를 출력하는 방법이다. 

 


 

lcd_display.c


/*
	입력 : s(크기) , n(출력할 수)
	출력 : LCD Display 형태로 n를 출력 
	조건 : s+2 열, 2s+3 행을 사용 
*/

#include <stdio.h>
#include <stdlib.h>

#define ROW(s) (2*s + 3)
#define COL(s) (s+2)

#define ROW_CHAR '@'
#define COL_CHAR '@'
#define SPACE ' '

void f0(int n, int s);
void f1(int n, int s);
void f2(int n, int s);
void f3(int n, int s);
void f4(int n, int s);
void f5(int n, int s);
void f6(int n, int s);

void lcd_display(int s, char *buf);

int main (int argc, char const* argv[])
{
	int s;
	char buf[10];
	
	scanf("%d %s", &s, buf);
	
	lcd_display(s, buf);

	return 0;
}


void lcd_display(int s, char *buf) {
	int i;
	char *p = buf;
	
	if (s == 0 && atoi(buf) == 0) {
		return ;
	}

	p = buf;
	while (*p != '\n' && *p != '\0') {
		f0(*p-'0', s);
		p++;
	}
	putchar('\n');
	
	for (i = 0; i < (ROW(s)-1)/2; i++) {	
		p = buf;
		while (*p != '\n' && *p != '\0') {
			f1(*p-'0', s);
			p++;
		}
		putchar('\n');
	}
	
	p = buf;
	while (*p != '\n' && *p != '\0') {
		f3(*p-'0', s);
		p++;
	}
	putchar('\n');

	for (i = 0; i < (ROW(s)-1)/2; i++) {
		p = buf;
		while (*p != '\n' && *p != '\0') {
			f4(*p-'0', s);
			p++;
		}
		putchar('\n');
	}
		
	p = buf;
	while (*p != '\n' && *p != '\0') {
		f6(*p-'0', s);
		p++;
	}
	putchar('\n');
}


// 가장 첫행 
void f0(int n, int s) {
	int i;
	char ch = COL_CHAR;
	
	if (n == 1 || n == 4){
		ch = SPACE;
	} 
	for (i = 0; i < COL(s)-1; i++) {
		putchar(ch);
	}
	putchar(SPACE);
}

void f1(int n, int s) {
	int i;
	char ch = ROW_CHAR;
	
	if (n == 1 || n == 2 || n == 3 || n == 7) {
		ch = SPACE;
	}
	putchar(ch);
	for (i = 0; i < COL(s)-3; i++) {
		putchar(SPACE);
	}
	f2(n, s);
}

void f2(int n, int s) {
	char ch = ROW_CHAR;
	
	if (n == 5 || n == 6){
		ch = ' ';
	}
	putchar(ch);
	putchar(SPACE);
}
// 중간 행 
void f3(int n, int s) {
	int i;
	char ch = COL_CHAR;
	
	if (n == 0 || n == 1 || n == 7){
		ch = ' ';
	}
	for (i = 0; i < COL(s)-1; i++) {
		putchar(ch);
	}
	putchar(SPACE);
}

void f4(int n, int s) {
	int i;
	char ch = ROW_CHAR;
	
	if (n == 1 || n == 3 || n == 4 || n == 5 || n == 7 || n == 9){
		ch = SPACE;
	}
	putchar(ch);
	for (i = 0; i < COL(s)-3; i++) {
		putchar(SPACE);
	}
	f5(n, s);
}

void f5(int n, int s) {
	char ch = ROW_CHAR;
	
	if (n == 2){
		ch = ' ';
	}
	putchar(ch);
	putchar(' ');
}

// 끝행 
void f6(int n, int s) {
	int i;
	char ch = COL_CHAR;
	
	if (n == 1 || n == 4 || n == 7){
		ch = SPACE;
	}
	for (i = 0; i < COL(s)-1; i++) {
		putchar(ch);
	}
	putchar(SPACE);
}


'알고리즘.데이터구조' 카테고리의 다른 글

HMAC-SHA1  (0) 2011.03.11
문제5 그래픽편집기  (0) 2011.02.18
문제4 LCD디스플레이  (0) 2011.02.18
문제3 여행  (0) 2011.02.18
문제2 지뢰찾기  (0) 2011.02.18
문제1 3n+1문제  (0) 2011.02.18

문제3 여행

알고리즘.데이터구조 2011. 2. 18. 11:40


 

여행에 참석한 학생들이 식비, 호텔비, 택시비,  비행기표를 한명씩 부담하고, 나중에 1센트 단위 내에서  

쓴 돈이 같아지고, 돈을 주고 받을 때 서로 전달 해야하는 최소액수를 구해보자.

 

입력

여행에 참석한 학생 수와 각 학생이 부담한 비용을 입력으로 받는다. 단 학생수는 1000명 이하이고, 

어떤 학생도 10,000.00 달러 이상 지출하지 않는다. 단위는 달려이고, 0이 입력되면 종료한다.

 

출력

각 학생이 사용한 금액이 같아지기 위해 전달되어야 하는 금액의 총합

 

ex)

입력

3

15.00

15.01

3.00

3.01

0

 

출력

$11.99

 

해결과정

각 학생이 소비한 금액의 평균을 구해서, 평균액보다 적은 돈을 낸 사람에 대해  평균액과 낸 금액의 차에 합을  

구하면 된다. 이 때 1센트 이내에  차이가 있어야 하기 때문에  평균액을 구할 때 소수 셋째짜리에서 반올림을 수행한다.

반올림을 위해, 평균액에 1000을 곱하고, 1의 자리에서 반올림 후 다시 1000으로 나눠주는 과정을 거치게 된다. 

 

trip_fee.c


/*
	입력 : 여행에 참여한 학생수 (정수 n <= 1000), 각 학생이 낸 경비 
	출력 : 각 학생이 사용한 금액이 같아지기 위한 금액 총합 	
*/

#include <stdio.h>
#include <stdlib.h>

double total_fee(double* fees, int n);

int main (int argc, char const* argv[])
{
	int i, n;
	double total, *fees;
	
	scanf("%d", &n);
	fees = (double*)malloc(n * sizeof(double));
	
	for (i = 0; i < n; i++) {
		scanf("%lf", fees + i);
	}
	
	total = total_fee(fees, n);
	
	printf("$%.2lf \n",  total);
	
	free(fees);
	
	return 0;
}


double total_fee(double* fees, int n) {
	int i, share, rem;
	float sum, d_share, total; 
		
	sum = d_share = total = 0.0;
	for (i = 0; i < n; i++) {
		sum += fees[i];
	}
	share = (sum * 1000) / n;
	
	if ((rem = share % 10) >= 5) {
		share += 10;
	}
	share -= rem;
	d_share = share / 1000.0;

	for (i = 0; i < n; i++) {
		if (fees[i] > d_share) {
			total += fees[i] - d_share;
		}
	}
	
	return total;
}


'알고리즘.데이터구조' 카테고리의 다른 글

HMAC-SHA1  (0) 2011.03.11
문제5 그래픽편집기  (0) 2011.02.18
문제4 LCD디스플레이  (0) 2011.02.18
문제3 여행  (0) 2011.02.18
문제2 지뢰찾기  (0) 2011.02.18
문제1 3n+1문제  (0) 2011.02.18

문제2 지뢰찾기

알고리즘.데이터구조 2011. 2. 18. 11:40


윈도우의 지뢰찾기 게임을 기억할 것이다. M x N 크기 지뢰밭 각 셀은 인접한 셀에 몇개의 지뢰가 존재하는지

나타내는 수를 가지고 있다.  *를 지뢰하고 하면...

 

 * . . .

  . . . . 

 . * . .

  . . . .

 

와 같은 지뢰밭은 다음과 같은 값을 가지게 된다.

 

* 1 0 0

2 2 1 0

1 * 1  0

1 1 1 0

 

입력 : 행의 개수 n, 열의 개수 m /   n행 m열의 지뢰밭 

출력 : 인접한 8개의 이웃에 있는 지뢰의 개수가 계산된 지뢰밭  출력

 

ex) 

입력  

4 4

* . . . 

. . . . 

. . . .

. * . .

 

출력

* 1 0 0

2 2 1 0

1 * 1 0

1 1 1 0

 

문제해결

지뢰가 아닌 모든 셀에 대해서 이웃하는 지뢰의 개수를 카운팅한다. 카운팅은 상 하 좌 우 인덱스를 변화시켜 지뢰의 개수를 

카운팅하되 행과 열에 대한 바운더리를 초과하지 않도록 검사를 수행한다.


mine_sweeper.c


/*
	입력 : 행과 열의 개수 n m / 지뢰밭 
	출력 : 이웃하는 지뢰개수가 계산된 지뢰밭 
*/

#include <stdio.h>
#include <stdlib.h>

#define MINE '*'
#define EMPTY '.'
#define MAX_BUF 200

typedef struct _Mine {
	int n, m;
	char *mines;
} Mine;


Mine *input();
void construct_mine(Mine *_mine);
void destruct_mine(Mine *_mine);

int count_mines(Mine *mine, int r, int c);
void output();


int main (int argc, char const* argv[])
{
	Mine *mine;
	
	while (mine = input()) {
		construct_mine(mine);
		output(mine);
		destruct_mine(mine);
	} 
	
	return 0;
}

Mine *input() {
	int m, n, i, j;
	Mine *mine;
	char buf[MAX_BUF];
	char *p_buf = buf;
	
	scanf("%d %d", &m, &n);
	getchar(); // 개행 문제를 버림 
		
	if (m == 0 && n == 0) {
		return 0;
	}
	
	mine = (Mine*)malloc(sizeof(Mine));
	mine->m = m;
	mine->n = n;
	mine->mines = (char*)malloc(m * n + 1);
	
	for (i = 0; i < m; i++) {
		p_buf = buf;
		fgets(buf, MAX_BUF, stdin);
		j = 0;
		while (*p_buf != '\0') {
			if (*p_buf == '*' || *p_buf == '.') {
				mine->mines[n*i + j] = *p_buf;
				j++;
			}
			p_buf++;
		}
	}	
	return mine;
}

// 모든 셀에 지뢰 개수를 카운팅 
void construct_mine(Mine *_mine) {
	int i, j;
	Mine *mine = _mine;
	int m = mine->m, n = mine->n;
	
	for (i = 0; i < m; i++) {
		for (j = 0; j < n; j++) {
			if (mine->mines[i*n + j] != '*') {
				mine->mines[i*n + j] = count_mines(mine, i, j);
			}
		}
	}
}

void destruct_mine(Mine *_mine) {
	free(_mine->mines);
	free(_mine);
}


//  특정 셀의 인접한 이웃의 지뢰의 개수를 카운팅 
int count_mines(Mine *mine, int r, int c) {
	int index, count = 0;
	int m = mine->m, n = mine->n;
	char *cell = mine->mines;
	
	if (r - 1 >= 0 && c - 1 >= 0) {
		index = (r - 1)*n + c - 1;
		if (*(cell + index) == '*') {
			count++;
		}
	}
	if (r - 1 >= 0) {
		index = (r - 1)*n + c;
		if (*(cell + index) == '*') {
			count++;
		}
	}
	if (r - 1 >= 0 && c + 1 < n) {
		index = (r - 1)*n + c + 1;
		if (*(cell + index) == '*') {
			count++;
		}
	}
	if (c - 1 >= 0) {
		index = r*n + c - 1;
		if (*(cell + index) == '*') {
			count++;
		}
	}
	if (c + 1 < n) {
		index = r*n + c + 1;
		if (*(cell + index) == '*') {
			count++;
		}
	}
	if (r + 1 < m && c - 1 >= 0) {
		index = (r + 1)*n + c - 1;
		if (*(cell + index) == '*') {
			count++;
		}
	}
	if (r + 1 < m) {
		index = (r + 1)*n + c;
		if (*(cell + index) == '*') {
			count++;
		}
	}
	if (r + 1 < m && c + 1 < n) {
		index = (r + 1)*n + c + 1;
		if (*(cell + index) == '*') {
			count++;
		}
	}
	return count;
}


// 결과 출력 
void output(Mine *mine) {
	int i;
	printf("Field #:");
	for (i = 0; i < mine->m * mine->n; i++) {
		if (*(mine->mines + i) == '*') {
			printf("%c ", *(mine->mines + i));
		} else {
			printf("%d ", *(mine->mines + i));
		}
		if (i % mine->n == mine->n - 1) {
			printf("\n");
		}
	}
	printf("\n");
}


'알고리즘.데이터구조' 카테고리의 다른 글

HMAC-SHA1  (0) 2011.03.11
문제5 그래픽편집기  (0) 2011.02.18
문제4 LCD디스플레이  (0) 2011.02.18
문제3 여행  (0) 2011.02.18
문제2 지뢰찾기  (0) 2011.02.18
문제1 3n+1문제  (0) 2011.02.18

문제1 3n+1문제

알고리즘.데이터구조 2011. 2. 18. 11:39

 

정수 n에서 n이 짝수면 2로 나누고, 홀수면 3을 곱하고 1을 더한다. 이렇게 만들어지는 수를 

다시 n으로 놓고,  n=1이 될 때까지 반복해서 나오는 수들의 개수를 정수 n의 사이클 길이(cycle length)라고 한다. 

(1을 포함)

 

i, j 두개의 수가 주어졌을 때, 두 수 사이의 모든 수(i, j 포함)들 중 최대 사이클 길이를 구하라 

 

입력 : i j     (  0 <= i, j <= 1000000)

출력 : i j cycle_length

 

ex) 입력 : 1 10

       출력 : 1 10 20

 

3n_1.c


/*
	입력 : 정수 i, j
	출력 : 정수 i, j, 최대 사이클 길이 
*/

#include <stdio.h>

int cycle_length(int num);

int main (int argc, char const* argv[])
{
	int left_bound, right_bound, max = 0;
	int i, cycle_len;
	
	scanf("%d %d", &left_bound, &right_bound);
	
	for (i = left_bound; i <= right_bound; i++) {
		cycle_len = cycle_length(i);
		if (cycle_len > max) {
			max = cycle_len;
		}
	}
	
	printf("%d %d %d \n", left_bound, right_bound, max);
	
	return 0;
}

int cycle_length(int num) {
	int n = num, cn = 1;
	
	while (n != 1) {
		if (n % 2) {
			n = 3*n + 1;
		} else {
			n = n >> 1;
		}
		cn++;
	}
	return cn;
}


'알고리즘.데이터구조' 카테고리의 다른 글

HMAC-SHA1  (0) 2011.03.11
문제5 그래픽편집기  (0) 2011.02.18
문제4 LCD디스플레이  (0) 2011.02.18
문제3 여행  (0) 2011.02.18
문제2 지뢰찾기  (0) 2011.02.18
문제1 3n+1문제  (0) 2011.02.18