[알고리즘] 알고리즘 글 목록

알고리즘.데이터구조 2013. 7. 8. 22:48


정렬 알고리즘


문제


암호화/해쉬



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

[알고리즘] 알고리즘 글 목록  (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

프로그래밍 문제 접근법

알고리즘.데이터구조 2011. 4. 26. 13:32



인터뷰에서 가장 주된 부분을 차지하는 것은 기술면접, 코딩 => 어려운 문제 => 능력을 보여줄 수 있는 기회
답이 보이지 않는 상황에서 문제를 어떤 식으로 해결하는지를  살펴보기 위한 문제들도 있으니 긴장은 하지말자!


1. 절차


1.1 시나리오
코딩문제는 인터뷰어와 일대일로 진행하는 것이 일반적.  
종이와 펜을 코드를 작성하라고 한다거나, 전에 문제를 설명해보라고 할 수 있다.


1.2 문제
짧은 시간안에 설명까지 할수 있어야 하기 때문에, 변별력 있는 적당히 어려운 문제가 출제된다.
(실전에 직접 적용할 수 있는 코드를 만드는 문제가 나올 가능성은 희박함)
문제의 난이도는 대체로 점점 어려워지는 순서로 배치된다 


1.3 어떤 언어를 선택할 것인가?
일반 프로그래밍 또는 개발업무를 지원했다면  C#, Java, C++,  C 같은 주류 언어를 제대로 쓸수있는 정도면 됨
인터뷰를 하러 가기 전에 자신이 사용할 모든 언어의 사용법 및 문법을 제대로 숙지해야함
(C++ 프로그래밍을 마지막으로 건드려본지 몇년 지났다면 적당한  C++ 레퍼런스 가이드를 펼쳐 중요한 내용 체크!)


1.4 의사소통의 중요성 
자신이 사용할 언어를 가다듬고 가능하면 가장 좋은 코드를 만들자.
인터뷰어가 정말로 원하는 것은 지원자가 문제를 푸는 각 단계들을 어떻게 진행하는지 보는 것임
지속적으로 무슨일을 하고 있는지 설명하도록 하자



2. 문제해결
인터뷰 문제를 해결하는 조직적인 방법을 알아보면,

1) 문제를 확실히 이해한다
   - 문제를 이해하지 못했을 경우 주저하지 말고 인터뷰어에게 문제에 대한 질문을 해야함 
2) 일단 문제를 이해하고 나면 몇 가지 예를 들어본다 
  - 예를 시도하다보면 문제를 어떻게 풀어야 할지 감을 잘을 수도 있다.
3) 문제 풀이에 사용할 알고리즘에 초점을 맞춘다 
  - 보통 이 과정은 시간이 오래 걸리는 단계임. 부담을 가지지 말고, 인터뷰어와 대화를 통해 무엇을 하고 있는지를 보여줘야함 
4) 알고리즘과 구현 방법을 알아내고 나면 인터뷰어에게 풀이를 설명한다.
5) 코딩을 할 때도 뭘 하고 있는지 설명한다. 
   - 조용히 코드만 적는 방법은 그리 좋지 않다. 
6) 필요하다면 질문을 한다
7) 코드를 완성하고 나면 바로 몇 가지 예를 시도해 보고 맞는지 확인한다 
8) 모든 오류 및 특별 케이스, 특히 경계 조건을 확인한다 

=> 코드가 제대로 만들어졌다는 판단이 들면 인터뷰어가 코드에 대한 질문을 몇 가지 던질 것이다.
보통 이런 추가 질문에는 실행시간이나 또 다른 구현 방법, 복잡도 등에 초점을 맞춘다 


2.1 문제를 풀다가 막히는 경우
인터뷰어는 문제에 대한 답을 바로 알아낼 수 없는 경우에 지원자가 어떤 식으로 반응하는지를 살펴보고 싶어하기 마련.
문제를 풀다가 갑자기 막히게 됐을 때 포기하거나 좌절하는 것은 최악의 대응책이다. 
계속해서 흥미를 보이고 풀려고 시도하는 모습을 보이자

* 예를 다시 따져본다
 - 특정 예에서 일반적인 경우로 확장을 해보고 그로부터 풀이를 도출해보자.
* 다른 자료 구조를 사용해 시도해 본다.
* 언어에서 그리 많이 쓰이지 않는 기능 또는 고급 기능을 고려해 보자. 
 - 다른 자료구조, 언어ㄱ의 고급 기능이 문제 풀이의 핵심이 되는 경우도 있다. 


3. 풀이 분석

3.1 빅 오 분석법(big-O analysis) 
입력 값의 개수에 따라 알고리즘이 수행되는데 걸리는 시간을 바탕으로 알고리즘의 효율성을 평가하는 실행 시간 분석법
(입력의 개수 n이 매우 큰 경우의 실행시간인 점근적인 실행시간을 따지기 때문에 상수항은 무시함                                                    
(n이 매우 커질 때 가장 큰 항만 남기고 다른 항은 무시함)


3.2 빅 오 분석법을 적용하는 방법
1) 입력 값이 무엇인지 확인하고 어떤 것을  n으로 놓아야 할지 결정한다.
2) 알고리즘에서 수행해야 할 연산 횟수를 n의 식으로 표현한다 
3) 차수가 제일 높은 항만 남긴다
4) 모든 상수 인수를 없앤다 


때론 최선 케이스,  평균 케이스, 최악 케이스의 실행 시간을 따져봐야 하는 문제도 생김. 








 


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

[알고리즘] 알고리즘 글 목록  (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

원 위에 나열된 수 제거하기

알고리즘.데이터구조 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