| 문제


비방향성 그래프 G의 커넥티드 컴포넌트를 의미하는 DFS를 구현하라. DFS 과정을 진행하는 동안, 작은 숫자를 가진 꼭짓점들을 먼저 방문하도록 설계하고, 컴포넌트 숫자는 1로 시작한다.


입력(표준 입력)

첫 번째 줄에는, 꼭짓점의 숫자 N을 입력한다.

다음 줄 부터, 그래프 G의 인접 리스트를 두 정수 x,y로 표현한다. 이것은 x로 시작해서 y로 끝나는 간선이 있음을 의미한다.


출력(표준 출력)

첫 번째 줄에는, 커넥티드 컴포넌트의 숫자를 출력한다.

다음 줄부터 N개의 줄에는, 각각의 꼭짓점의 커넥티드 숫자를 출력한다.



example)

입력 

출력 

6

1 2

1 4

2 5

3 6

2

1

1

2

1

1

2





| 소스 코드

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

#define TRUE		1
#define FALSE		0

int numV;
int * list;
int * Qlist;
int * rep;

typedef struct _vertex;

typedef struct _vertex
{
	int groupname;
	int value;
	int rank;
	struct _vertex * parent;
} Vertex;

Vertex * vertex;

void MAKE_SET(Vertex * x, int value)
{
	x->value = value;
	x->parent = x;
	x->rank = 0;
}

Vertex * FIND_SET(Vertex * x)
{
	if(x != x->parent)
		x->parent = FIND_SET(x->parent);
	return x->parent;
}

void LINK(Vertex * x, Vertex * y)
{
	if(x->rank > y->rank){
		y->parent = x;			// 랭크가 큰 놈이 부모가 되도록!
	}
	else{
		x->parent = y;
		if(x->rank == y->rank){
			y->rank = y->rank + 1;
		}
	}
}

void UNION(Vertex * x, Vertex * y)
{
	LINK(FIND_SET(x), FIND_SET(y));
}

int SAME_COMPONENT(Vertex * x, Vertex * y)
{
	if(FIND_SET(x) == FIND_SET(y))
		return TRUE;
	else
		return FALSE;
}

int main(void)
{
	int * tmp_list;
	int v1, v2;
	int i=0, j=0, tmp=0;
	int order = 0;
	int compNUM = 0;

	scanf("%d", &numV);
	vertex = (Vertex*)malloc(sizeof(Vertex)*(numV+1));
	list = (int*)malloc(sizeof(int)*(numV+1));
	tmp_list = (int*)malloc(sizeof(int)*(numV+1));
	
	for(i=1; i<=numV; i++)
		MAKE_SET(&vertex[i], i);

	while(scanf("%d %d", &v1, &v2) != EOF){	
		if(FIND_SET(&vertex[v1]) != FIND_SET(&vertex[v2])){
			UNION(&vertex[v1], &vertex[v2]);
		}
	}
	for(i=1; i<=numV; i++){
		list[i] = FIND_SET(&vertex[i])->value;
		tmp_list[i] = FIND_SET(&vertex[i])->value;
	}

	for(i=1; i<=numV; i++)
	{
		tmp = list[i];
		if(tmp != 0)
		{
			compNUM ++;
			for(j=i+1; j<=numV; j++){
				if(tmp == list[j])
					list[j] = 0;
			}
		}
	}
	Qlist = (int*)malloc(sizeof(int)*(compNUM+1));
	order = 1;
	for(i=1; i<=numV; i++){
		if(list[i] != 0){
			Qlist[order++] = list[i];
		}
	}
	for(i=1; i<=numV; i++){
		for(j=1; j<=numV; j++){
			if(tmp_list[i] == Qlist[j]){
				list[i] = j;
			}
		}
	}
	
	printf("%d\n", compNUM);
	for(i=1; i<=numV; i++)
		printf("%d\n", list[i]);

	return 0;
}


| 문제


입력(표준 입력)

각각의 줄에는 최대 3개의 정수들을 포함하고 있어야 한다.

3개의 입력 정수들 중,

첫 번쨰 숫자가 0이면 결과를 출력하고 프로그램을 종료한다. (terminate)

첫 번째 숫자가 1이면 두 번째 숫자를 삽입한다. (insert)

첫 번째 숫자가 2이면 가장 큰 숫자를 추출한다. (extract)

첫 번째 숫자가 3이면, 두 번째 숫자 인덱스의 원소를 세 번째 숫자로 바꾼다.

우선순위 큐의 인덱스는 1로 시작한다고 가정하자.

우선순위 큐의 최대 인덱스 값은 100000이다.


출력(표준 출력)

첫 번째 줄에, 추출된 원소들을 출력한다.

두 번째 줄에, 현재 힙을 출력한다.


example)


입력 

출력 

1 16

1 15

1 10

1 14

1 7

1 9

1 3

1 2

1 8

1 1

3 2 4

2

2

0

16 14

10 8 9 4 7 1 3 2 


| 소스 코드

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

#define minus_inf -32767

int PARENT(int index){ return index/2; }
int LCHILD(int index){ return index*2; }
int RCHILD(int index){ return index*2+1; }

void array_swap(int arr[], int a, int b)
{
	int temp;
	temp = arr[a];
	arr[a] = arr[b];
	arr[b] = temp;
}

void Heapify(int arr[], int current, int length)
{
	int left, right, largest;
	left=LCHILD(current);
	right=RCHILD(current);

	if((right<=length) && (arr[right]>arr[current]))
		largest = right;
	else
		largest = current;

	if((left<=length) && (arr[left]>arr[largest]))
		largest = left;

	if(largest != current)
	{
		array_swap(arr, current, largest);
		Heapify(arr, largest, length);
	}
}

void PRINT(int arr[], int length)
{
	int i=0;
	for(i=1; i<=length; i++)
		printf("%d ", arr[i]);
}

int EXTRACT_MAX(int arr[], int length)
{
	if(length < 1)		// "heap underflow"
		return minus_inf;
	int max = arr[1];
	arr[1] = arr[length];
	length --;
	Heapify(arr, 1, length);
	return max;
}

void INCREASE_KEY(int arr[], int index, int key)
{
	int tmp=0;
	if(key < arr[index])		// not increasing, then fail.
		return;

	arr[index] = key;
	while(index>1 && arr[PARENT(index)]<arr[index])
	{
		/* EXCHANGE CURRENT WITH PARENT */
		tmp = arr[index];
		arr[index] = arr[index/2];
		arr[index/2] = tmp;

		index = PARENT(index);
	}
}

void INSERT(int arr[], int length, int key)
{
	arr[length] = minus_inf;
	INCREASE_KEY(arr, length, key);
}

int main(void)
{
	int arr[100000];
	int ext[100000];
	int length=0, extlength=0;

	int op, tmp, i;
	int index, num;

	int quit=0;

	//INSERT(arr, length, 1); length++;
	//INSERT(arr, length, 2); length++;

	while(quit==0)
	{
		scanf("%d", &op);
		switch(op)
		{
		case 0:// print
			quit=1;		// terminate this program.
			break;

		case 1:// insert
			scanf("%d", &num);
			length++;
			arr[length] = num;
			INCREASE_KEY(arr, length, num);
			break;

		case 2:// extract
			extlength++;
			ext[extlength] = arr[1];

			tmp = arr[1];
			arr[1] = arr[length];
			arr[length] = tmp;

			length--;
			Heapify(arr, 1, length);
			break;

		case 3:// replace
			scanf("%d %d", &index, &num);
			arr[index] = num;
			if(index != 1 && arr[index] > arr[PARENT(index)])
				INCREASE_KEY(arr, index, num);
			else
				Heapify(arr, index, length);
			break;
	
		default:
			break;
		}
	}

	for(i=1; i<=extlength; i++)
		printf("%d ", ext[i]);

	printf("\n");
	for(i=1; i<=length; i++)
		printf("%d ", arr[i]);

	return 0;
}


| 문제


입력(표준 입력)

첫번째 줄에, 입력할 숫자들의 개수 N와 정수 k를 입력합니다.

다음줄 부터 N개의 줄만큼, 각각의 줄마다 하나의 입력 변수를 입력해야 합니다.


출력(표준 출력)

첫 번째 줄에는, 내림차순으로 가장 큰 k개의 원소들을 출력해 냅니다.

두 번째 줄에는, 가장 큰 k 원소들을 추출해낸 후에 힙을 출력해 냅니다.

 

ex) 

 

입력 

출력 

10 4

16

14

10

8

7

9

3

2

4

1

16 14 10 9

8 7 3 4 2 1 

 

 | 소스 코드 

#include <stdio.h>

void array_swap(int * arr, int a, int b)
{
	int temp;
	temp = arr[a];
	arr[a] = arr[b];
	arr[b] = temp;
}

void Heapify(int * arr, int parent_position, int heap_size)
{
	int left, right, largest;
	left=2*parent_position+1;
	right=2*parent_position+2;

	if((left<heap_size)&&(arr[left]>arr[parent_position]))
		largest = left;
	else
		largest = parent_position;

	if((right<heap_size)&&(arr[right]>arr[largest]))
		largest = right;

	if(largest != parent_position)
	{
		array_swap(arr, parent_position, largest);
		Heapify(arr, largest, heap_size);
	}
}

void Build_Heap(int * arr, int length)
{
	int parent_position;

	for(parent_position=length/2-1; parent_position>=0; parent_position--)
		Heapify(arr, parent_position, length);
}

void Heap_Sort(int * arr, int length, int k)
{
	Build_Heap(arr, length);
	int last_row;
	int count = 0;

	for(last_row = length-1; last_row>0; last_row--)
	{
		if(count == k)
			break;
		array_swap(arr, 0, last_row);
		length--;
		count ++;

		Heapify(arr, 0, length);
	}
}
int main(void)
{
	int arr[100000];
	int length = 10;
	int N, k, i;

	// input
	scanf("%d %d", &N, &k);
	for(i=0; i<N; i++)
	{
		scanf("%d", &arr[i]);
	}
	Heap_Sort(arr, N, k);

	// output
	for(i=N-1; i>(N-1)-k; i--)
		printf("%d ", arr[i]);

	printf("\n");
	for(i=0; i<=(N-1)-k; i++)
		printf("%d ", arr[i]);

	printf("\n");

	return 0;
}


| 문제


방향성 그래프 G에서 모든 간선들의 타입을 출력해내는 DFS(깊이 우선 탐색)을 구현하여라. DFS 과정을 진행하는 동안, 작은 숫자의 꼭짓점부터 방문하도록 설계하라. 


입력(표준 입력)

첫 번째 줄에, 꼭짓점의 개수 N을 입력한다.

두번 째 줄부터, 그래프 G의 인접 리스트가 x,y 두 정수로 표현이 된다. 이것은 x로 출발해서 y로 도착하는 간선이 있음을 의미한다.


출력(표준 출력)

G의 각각의 간선 타입들과 함께 간선들을 출력해내라. 간선들의 타입 표현은 다음과 같다.

1: 트리 엣지

2: 백 엣지

3: 포워드 엣지

4: 크로스 엣지

각각의 줄에는 세 개의 정수 x,y,z가 출력되어야 한다. 이것들은 x에서 출발하여 y로 도착하는 간선이 있으며 그 간선이 z의 타입을 가진다는 것을 의미한다.



입력 

출력 

6

1 2

1 4

2 5

3 5

3 6

4 2

5 4

6 6

1 2 1

1 4 3

2 5 1

3 5 4

3 6 1

4 2 2

5 4 1

6 6 2 


| 소스 코드

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

#define WHITE			0
#define GRAY			1
#define BLACK			2

#define TREE_EDGE		1
#define BACK_EDGE		2
#define FORWARD_EDGE	3
#define CROSS_EDGE	4

unsigned int time = 0;
unsigned int numV = 0;

typedef struct _vertex
{
	int color;
	int d;
	int f;
	int pred;
} Vertex;

// 구조체 멤버 중 자기 구조체를 타입으로 하는 포인터 next을 사용하는 이유는,
// 리스트 형태로 연결하고자 하기 위함.
typedef struct _edge
{
	int toV;
	int type;
	struct _edge * next;
} Edge;

// 각 Vertxt 마다 Adjacency list 구조체가 하나씩 배당되는 것으로 생각
Vertex SetV[1000];
Edge * adjlist[1000]={NULL,};

void addEdge(int fromV, int toV)
{
	Edge * newEdge;
	Edge * temp;
	temp = adjlist[fromV];

	newEdge = (Edge*)malloc(sizeof(Edge));
	newEdge->toV = toV;
	newEdge->next = NULL;

	if(adjlist[fromV] == NULL)
	{
		adjlist[fromV] = newEdge;
	}
	else
	{
		while(temp->next != NULL)
		{
			temp = temp->next;
		}
		temp->next = newEdge;
	}
}

void DFS_Visit(int fromV)
{
	Edge * edge_fromV;
	edge_fromV = adjlist[fromV];

	time ++;
	/* DISCOVERY */
	SetV[fromV].color = GRAY;
	SetV[fromV].d = time;

	while(edge_fromV != NULL)
	{
		int toV;
		toV = edge_fromV->toV;

		switch(SetV[toV].color)
		{
		case WHITE:
			edge_fromV->type = TREE_EDGE;		// 1
			SetV[toV].pred = fromV;
			DFS_Visit(toV);
			break;

		case GRAY:
			edge_fromV->type = BACK_EDGE;		// 2
			break;

		case BLACK:
			if(SetV[fromV].d < SetV[toV].d)
				edge_fromV->type = FORWARD_EDGE;// 3
			else if(SetV[fromV].d > SetV[toV].d)
				edge_fromV->type = CROSS_EDGE;	// 4
			break;

		default:
			break;
		}

		edge_fromV = edge_fromV->next;
	}

	/* FINISHED */
	SetV[fromV].color = BLACK;
	time ++;
	SetV[fromV].f = time;
}

void DFS(void)
{
	int i;
	for(i=1; i<=numV; i++)
	{
		SetV[i].color = WHITE;
		SetV[i].pred = NULL;
	}
	time = 0;
	for(i=1; i<=numV; i++)
	{
		if(SetV[i].color == WHITE)
		{
			DFS_Visit(i);
		}
	}
}

int main(void)
{
	int i=0;
	int fromV, toV;
	Edge * temp;

	scanf("%d", &numV);
	while(scanf("%d %d", &fromV, &toV) != EOF)
	{
		addEdge(fromV, toV);
	}

	DFS();

	for(i=1; i<=numV; i++)
	{
		temp = adjlist[i];
		while(temp != NULL)
		{
			printf("%d %d %d \n", i, temp->toV, temp->type);
			temp = temp->next;
		}
	}
	return 0;
}


HBE-MCU-All in One 에서 ADC 모듈을 이용하면

햇빛 밝기를 측정할 수 있습니다. 광전압이라는 단어가 없긴 하지만,

햇빛 밝기가 높을 수록 전압이 세지므로 광전압이라고 합시다.


ADC 모듈을 손으로 가리면 광전압의 세기가 줄어들며, 다시 손을 치우면 광전압의 세기가 원래대로 돌아옵니다.


일반적인 환경에서는 ADC모듈로 측정된 전압이 약 2V 후반대 정도이며,

손으로 완전 햇빛을 가린 경우 1V 아래로 떨어지게 됩니다.


다음 소스 코드의 실행파일은 ADC모듈을 손으로 가리는 경우 Warning 이 뜨도록 합니다.



#include <avr/io.h> #include <avr/interrupt.h> #define TRUE 1 #define FALSE 0 #define LCD_CTRL PORTG #define LCD_DATA PORTA #define LCD_RS 0x01 // PG0 #define LCD_RW 0x02 // PG1 #define LCD_E 0x04 // PG2 volatile unsigned int AdData = 0; volatile unsigned int t2_100 = 0; volatile unsigned int count = 0; void delay(unsigned long x) { while(x--); } void EnablePulse(void) { LCD_CTRL |= LCD_E; asm("NOP"); LCD_CTRL &= ~LCD_E; } void sendLCDcommand(unsigned char command) { LCD_CTRL &= ~LCD_RS; LCD_DATA = command; EnablePulse(); delay(20); } void InitLCD(void) { delay(20000); LCD_CTRL &= ~LCD_RW; sendLCDcommand(0x38); sendLCDcommand(0x0C); sendLCDcommand(0x01); delay(1000); } void sendLCDdata(unsigned char data) { LCD_CTRL |= LCD_RS; LCD_DATA = data; EnablePulse(); delay(20); } void DispString(char * str) { while(*str) { sendLCDdata(*str); str++; } } void Locate(int x, int y) { unsigned char RamAddr; if(x==0) RamAddr = 0x80+y; else RamAddr = 0xC0+y; sendLCDcommand(RamAddr); } int main(void) { unsigned int AdData = 0; unsigned int Voltage100 = 0; unsigned char value_1 = 0, value_p1 = 0, value_p01 = 0; unsigned char temp = 0; // 포트 F - ADC, 포트 A와 G는 TextLCD에 연결. DDRF = 0x00; DDRA = 0xFF; DDRG = 0x07; // B와 G 포트를 출력으로 지정. PORTA = 0x00; PORTG = 0x00; // B와 G 포트 값의 초기값 지정. InitLCD(); /* TextLCD에 "CDS_OUT:_.__V"을 표시해줌.(_.__에 숫자가 채워짐) */ Locate(0,0); DispString("CDS_OUT"); Locate(0,7); sendLCDdata(':'); Locate(0,9); sendLCDdata('.'); Locate(0,12); DispString("V"); // AD 변환 설정 ADMUX = 0x00; // ADC0 선택 / 0번 채널 / 채널 초기 설정 ADCSRA = 0x87; // 10000111 / ADC 허가, 8KSPS 표본화 주파수 while(1) { ADCSR |= 0x40; // ADSC AD 개시(Start) while((ADCSRA & 0x10) == 0x00); // ADIF AD 다 될 때까지 기다림. AdData = ADC; // 전압이 디지털로 변환된 값 읽어오기. Voltage100 = AdData * 0.48828125; // AD값을 전압 값으로 변환. // 1의 자리수. value_1 = Voltage100 / 100; temp = Voltage100 % 100; // 소수점 이하 첫째 자리 수 value_p1 = temp / 10; // 소수점 이하 둘째 자리 수 value_p01 = temp % 10; // 숫자를 LCD에 표시하기 위해 문자 코드로 변환. value_1 = value_1 + 0x30; value_p1 = value_p1 + 0x30; value_p01 = value_p01 + 0x30; // 값들을 표시. Locate(0,8); sendLCDdata(value_1); Locate(0,10); sendLCDdata(value_p1); Locate(0,11); sendLCDdata(value_p01); count ++; // 표시할 때마다 한 번 사이클 도는 것으로 생각. if(count == 10) count = 0; if(Voltage100 <= 100) // 1.00 V 아래로 떨어진 경우, { Locate(1,0); // 두 번째 줄에 DispString("Warning..."); // 경고 표시. if(count >= 5) // 약 5번의 사이클이면 0.5초 정도로 예상. { Locate(1,0); DispString(" "); // 0.5초마다 깜빡임. } } else { Locate(1,0); DispString(" "); } delay(60000); } }


이전에 동영상으로 소개를 드린 비밀번호 시스템 만들기 소스 코드를 공개합니다.

EEPROM을 사용하여 비밀번호를 저장하고,

비밀번호를 확인하는 간단한 MCU 시스템을 만들게 한 c 소스 코드입니다.


#include <avr/io.h> #include <avr/interrupt.h> #include <avr/eeprom.h> // for eeprom #include "EEPROM.h" int main(void) { unsigned char password[4]; unsigned char input[4]; unsigned char i=0; int check = 0; int step = 0; int count = 0; DDRB = 0xFF; DDRG = 0xFF; DDRF = 0x00; DDRE = 0xFF; PORTB = 0x00; PORTG = 0xFF; Init_Timer(); sei(); // 제일 처음에는 FND에 아무것도 표시되지 않는다. digit3=digit2=digit1=digit0=16; while(1) { if(KeyPressed) { KeyPressed = FALSE; switch(key) { case 0x0A: // * 키 // 비밀번호 입력 부분. step = 2; count = 0; digit3=digit2=digit1=digit0=3; // 3333 표시. break; case 0x0C: // # 키 // 비밀번호 설정 부분. step = 1; // 비밀번호 설정 시작! if(check == 0) { digit3=digit2=digit1=digit0=0; // 0000 표시 check = 1; // check가 1이어야 입력 받기 가능. } // 비밀번호 설정이 종료. else { digit3=digit2=digit1=digit0=2; // 2222 표시. /* Write password to eeprom */ write_eeprom(0, password[0]); write_eeprom(1, password[1]); write_eeprom(2, password[2]); write_eeprom(3, password[3]); check = 0; } break; default: // *,# 키 말고 일반 숫자키를 누르는 경우 if(step == 1 && check==1) // 비밀번호 설정시 입력 { password[3] = password[2]; password[2] = password[1]; password[1] = password[0]; password[0] = key; digit3 = digit2; digit2 = digit1; digit1 = digit0; digit0 = 1; } else if(step == 2) // 비밀번호 체크시 입력 { count ++; input[3] = input[2]; input[2] = input[1]; input[1] = input[0]; input[0] = key; if(count == 4) // 4번 눌렀을 때, 비밀번호 체크. { count = 0; // EEPROM에 저장된 비밀번호를 불러옴. for(i=0; i<4; i++) password[i] = read_eeprom(i); /* 이 strcmp는 제가 직접 만든 함수입니다. * 같으면 TRUE를 반환 합니다. */ if(strcmp(input, password)) // 문을 여는 데 성공. digit3=digit2=digit1=digit0=7; // 7777 표시. else // 문을 여는 데 실패. digit3=digit2=digit1=digit0=4; // 4444 표시. } } break; } // switch(key) end } // if(KeyPressed) end } // Infinite loop end. }


+ Recent posts