| 문제


주어진 그래프가 만약 DAG(Directed Acyclic Graph, 방향성 비사이클 그래프)라면, 그 그래프의 꼭짓점들을 위상 정렬 하는 프로그램을 구현하라. DFS(Depth-First Search, 깊이 우선 탐색) 과정을 진행하는 동안, 작은 숫자의 꼭짓점들을 먼저 방문하도록 설계해야 한다.


입력(표준 입력)

첫 번째 에는 꼭짓점의 개수를 입력한다.

다음 줄부터, 그래프 G의 인접 리스트가 서로 연결되어 있는 꼭짓점인 x와 y로 표현되어야 한다. 이 것은 꼭짓점 x에서 꼭짓점 y로 나아가는 간선이 존재함을 의미한다.


출력(표준 출력)

첫 번째 줄에는, 주어진 그래프 G가 DAG라면 1을 출력하고, 아니면 0을 출력하게 한다.

그리고 그래프가 DAG이면 그 다음 줄에, 위상 순서대로 꼭짓점들을 출력해야 한다.


example)

입력

출력 

9

1 4

1 5

2 5

4 5

4 6

6 9

7 6

7 8

8 9

EOF 입력(윈도우에서는 Ctrl+Z)

1

7 8 3 2 1 4 6 9 5 





| 소스 코드


#include <stdio.h>
#include <stdlib.h>
#include <string.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

#define TRUE			1
#define FALSE			0

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

typedef struct _VertexInfo{
	int out_degree;
	int * list;
} VertexInfo;

Vertex * vertex;
VertexInfo * vertexInfo;
int numV, time;
int * topoList;
int topo_num=0;
int isDAG = TRUE;

void addEdge(int fromV, int toV){
	int i=0;
	int cur=0;

	for(i=0; i < numV; i++)
	{
		if(vertexInfo[fromV].list[i] == 0)
			break;
		cur ++;
	}
	vertexInfo[fromV].list[cur] = toV;
}

void DFS_Visit(int fromV){
	int i=0, toV;

	/* DISCOVERED */
	time++;
	vertex[fromV].color = GRAY;
	vertex[fromV].d = time;

	for(i=0; i < vertexInfo[fromV].out_degree; i++){
		toV = vertexInfo[fromV].list[i];
		switch(vertex[toV].color)
		{
		case WHITE:
			DFS_Visit(toV);
			break;

		case GRAY:
			isDAG = FALSE;
			break;

		case BLACK:
			break;
		default:
			break;
		}
	}

	/* FINISHED */
	vertex[fromV].color = BLACK;
	topoList[numV-(topo_num++)] = fromV;
	time ++;
	vertex[fromV].f = time;
}

void Sort(int * list, int num)
{
	int i=0, j=0, tmp;

	for(i=0; i < num; i++)
	{
		for(j=i+1; j < num; j++)
		{
			if(list[i] > list[j])
			{
				tmp = list[i];
				list[i] = list[j];
				list[j] = tmp;
			}
		}
	}
}


void DFS(void)
{
	int i;
	for(i=1; i <=numV; i++)
	{
		vertex[i].d = 0;
		vertex[i].f = 0;
		vertex[i].color = WHITE;
		Sort(vertexInfo[i].list, vertexInfo[i].out_degree);
	}

	time = 0;
	for(i=1; i <=numV; i++)
	{
		if(vertex[i].color == WHITE)
		{
			DFS_Visit(i);
		}
	}
}


int main(void)
{
	int i=0, j=0;
	int fromV, toV;

	scanf("%d", &numV);

	/* INITIALIZATION START! */
	vertexInfo = (VertexInfo*)malloc(sizeof(VertexInfo)*(numV+1));
	for(i=1; i <=numV; i++){
		vertexInfo[i].list = (int*)malloc(sizeof(int)*numV);
		vertexInfo[i].out_degree = 0;
	}
	for(i=1; i <=numV; i++){
		for(j=0; j < numV; j++){
			vertexInfo[i].list[j] = 0;
		}
	}
	vertex = (Vertex*)malloc(sizeof(Vertex)*(numV+1));
	topoList = (int*)malloc(sizeof(int)*(numV+1));
	/* INITIALIZATION END! */
	

// INPUT
	while(scanf("%d %d", &fromV, &toV)!=EOF){
		addEdge(fromV, toV);
		vertexInfo[fromV].out_degree ++;
	}
	DFS();

// OUTPUT
	printf("%d\n", isDAG);
	if(isDAG)
	{
		for(i=1; i <=numV; i++)
			printf("%d ", topoList[i]);
	}

	return 0;
}


| 문제


비방향성 그래프 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;
}


+ Recent posts