괄호 

시간 제한메모리 제한제출정답맞힌 사람정답 비율
1 초 128 MB 199349 93844 67449 45.933%

문제

괄호 문자열(Parenthesis String, PS)은 두 개의 괄호 기호인 ‘(’ 와 ‘)’ 만으로 구성되어 있는 문자열이다. 그 중에서 괄호의 모양이 바르게 구성된 문자열을 올바른 괄호 문자열(Valid PS, VPS)이라고 부른다. 한 쌍의 괄호 기호로 된 “( )” 문자열은 기본 VPS 이라고 부른다. 만일 x 가 VPS 라면 이것을 하나의 괄호에 넣은 새로운 문자열 “(x)”도 VPS 가 된다. 그리고 두 VPS x 와 y를 접합(concatenation)시킨 새로운 문자열 xy도 VPS 가 된다. 예를 들어 “(())()”와 “((()))” 는 VPS 이지만 “(()(”, “(())()))” , 그리고 “(()” 는 모두 VPS 가 아닌 문자열이다. 

여러분은 입력으로 주어진 괄호 문자열이 VPS 인지 아닌지를 판단해서 그 결과를 YES 와 NO 로 나타내어야 한다. 

입력

입력 데이터는 표준 입력을 사용한다. 입력은 T개의 테스트 데이터로 주어진다. 입력의 첫 번째 줄에는 입력 데이터의 수를 나타내는 정수 T가 주어진다. 각 테스트 데이터의 첫째 줄에는 괄호 문자열이 한 줄에 주어진다. 하나의 괄호 문자열의 길이는 2 이상 50 이하이다. 

출력

출력은 표준 출력을 사용한다. 만일 입력 괄호 문자열이 올바른 괄호 문자열(VPS)이면 “YES”, 아니면 “NO”를 한 줄에 하나씩 차례대로 출력해야 한다. 

예제 입력 1 복사

6
(())())
(((()())()
(()())((()))
((()()(()))(((())))()
()()()()(()()())()
(()((())()(

예제 출력 1 복사

NO
NO
YES
NO
YES
NO

예제 입력 2 복사

3
((
))
())(()

예제 출력 2 복사

NO
NO
NO

 

 

'{'를 +, '}' 를 -라 생각하고

하나의 변수를 0으로 설정한 후, 최종 결과가 0이면 된다.

하지만, } { 의 경우 vps 형태가 아니지만 위 조건을 만족하므로

이 경우를 잡기 위해, 위에서 설정한 변수가 음수가 되는 순간 vps가 아닌걸로 판단해야 한다. 

 

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

char is_vps(char* input, int size) {
	int check = 0;
	for (int i = 0; i < size; i++) {
		if(check>=0)
		{
			if (input[i] == '(')
				check++;
			else if (input[i] == ')')
				check--;
			else continue;
		}
		else
			return 0;
	}
	if (check == 0)
		return 1;
	else
		return 0;
}
int main() {
	int size = 0;
	scanf("%d", &size);

	char** p = (char**)malloc(sizeof(char*) * size);
	for (int i = 0; i < size; i++) {
		p[i] = (char*)malloc(sizeof(char) * 51); //문제에서 최대 길이가 50이므로, null값까지 생각하여 51
		scanf("%s", p[i]);
	}

	//check and print
	for (int i = 0; i < size; i++) {
		if (is_vps(p[i], 51))
			printf("YES\n");
		else
			printf("NO\n");
	}
	

	//free
	for (int i = 0; i < size; i++)
		free(p[i]);
	free(p);

	return 0;
}

'알고리즘 > 백준' 카테고리의 다른 글

[백준] 2292 벌집  (0) 2024.02.26
[백준] 10814 나이순 정렬  (0) 2024.02.25
[백준] 2798 블랙잭  (1) 2024.02.25
[백준] 1929 소수 구하기  (0) 2024.02.22
[백준] 1920 수 찾기  (0) 2024.02.19

블랙잭 

시간 제한메모리 제한제출정답맞힌 사람정답 비율
1 초 128 MB 171794 85684 65577 48.618%

문제

카지노에서 제일 인기 있는 게임 블랙잭의 규칙은 상당히 쉽다. 카드의 합이 21을 넘지 않는 한도 내에서, 카드의 합을 최대한 크게 만드는 게임이다. 블랙잭은 카지노마다 다양한 규정이 있다.

한국 최고의 블랙잭 고수 김정인은 새로운 블랙잭 규칙을 만들어 상근, 창영이와 게임하려고 한다.

김정인 버전의 블랙잭에서 각 카드에는 양의 정수가 쓰여 있다. 그 다음, 딜러는 N장의 카드를 모두 숫자가 보이도록 바닥에 놓는다. 그런 후에 딜러는 숫자 M을 크게 외친다.

이제 플레이어는 제한된 시간 안에 N장의 카드 중에서 3장의 카드를 골라야 한다. 블랙잭 변형 게임이기 때문에, 플레이어가 고른 카드의 합은 M을 넘지 않으면서 M과 최대한 가깝게 만들어야 한다.

N장의 카드에 써져 있는 숫자가 주어졌을 때, M을 넘지 않으면서 M에 최대한 가까운 카드 3장의 합을 구해 출력하시오.

입력

첫째 줄에 카드의 개수 N(3 ≤ N ≤ 100)과 M(10 ≤ M ≤ 300,000)이 주어진다. 둘째 줄에는 카드에 쓰여 있는 수가 주어지며, 이 값은 100,000을 넘지 않는 양의 정수이다.

합이 M을 넘지 않는 카드 3장을 찾을 수 있는 경우만 입력으로 주어진다.

출력

첫째 줄에 M을 넘지 않으면서 M에 최대한 가까운 카드 3장의 합을 출력한다.

예제 입력 1 복사

5 21
5 6 7 8 9

예제 출력 1 복사

21

예제 입력 2 복사

10 500
93 181 245 214 315 36 185 138 216 295

예제 출력 2 복사

497

 

 

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <math.h>
#include <stdlib.h>

//long factorial(int n) {
//	long temp = 1;
//	for (int i = 1; i <= n; i++)
//		temp *= i;
//	return temp;
//}
//
//long binomial_coefficient(int n, int k) {
//	if (k >= 0 && k <= n)
//		return factorial(n) / (factorial(k) * factorial(n - k));
//	return 0;
//}

void get_all_sum(int* input, long* output, int size, int boundary) {
	int i = 0, j = 1, k = 2;
	int index = 0;
	for (i = 0; i < j; i++) {
		for (j = i + 1; j < k ; j++) {
			for (k = j + 1; k < size; k++) {
				long temp = input[i] + input[j] + input[k];
				if (temp <= boundary)
					output[index++] = temp;
			}
		}
	}
	return;
}

int main() {
	int size = 0, boundary = 0;
	long long size_of_array_sum;
	scanf("%d %d", &size, &boundary);
	int* array = (int*)malloc(sizeof(int) * size);
	size_of_array_sum = (size * (size - 1) * (size - 2)) / 6;//binomial_coefficient(size, 3);

	long* sum_array = (long*)malloc(sizeof(long) * size_of_array_sum);
	int* diff_array = (int*)malloc(sizeof(int) * size_of_array_sum);

	for (int i = 0; i < size; i++) {
		scanf("%d", &array[i]);
	}

	// nC3으로 가능한 조합 합 모두 sum_array에 입력
	get_all_sum(array, sum_array, size, boundary);

	//boundary와 합 배열의 절대값 차이 계산
	for (int i = 0; i < size_of_array_sum; i++) {
		diff_array[i] = abs(boundary - sum_array[i]);
	}

	//계산한 절대값 차이 중 가장 작은 값의 인덱스 구하기
	int min = 300001; //문제에서 나올 수 있는 boundary 최대값 + 1
	int index_of_min = 0; //절대값 차가 가장 적은 sum_array의 index;
	for (int i = 0; i < size_of_array_sum; i++) {
		if (diff_array[i] < min) {
			min = diff_array[i];
			index_of_min = i;
		}
	}

	printf("%d", sum_array[index_of_min]);
	free(array);
	free(sum_array);
	free(diff_array);

}

 

가능한 모든 조합의 합을 저장하기 위한 size를 계산하기 위해서, 이항계수를 사용하려 시도했고, 이를 위해 factorial함수를 구현했지만, 수가 조금만 커저도 long long으로도 저장할 수 없어 다른 방법을 선택하였다. 

nCr에서 r값이 고정되어 있으므로, n! / {r!*(n-r)!} 을 계산하는 대신에 n(n-1)(n-2) / 6 을 사용하였다.

 

3중 for문을 이용해 모든 조합을 구하는 로직도, for문을 작성할때 중괄호 내 함수 동작 조건과 실행 후 연산을 신경써서 작성하면 쉽게 구현할 수 있다.

'알고리즘 > 백준' 카테고리의 다른 글

[백준] 10814 나이순 정렬  (0) 2024.02.25
[백준] 9012 괄호  (0) 2024.02.25
[백준] 1929 소수 구하기  (0) 2024.02.22
[백준] 1920 수 찾기  (0) 2024.02.19
[백준] 1676 팩토리얼 0의 개수  (0) 2024.02.17

소수 구하기 

 
시간 제한메모리 제한제출정답맞힌 사람정답 비율
2 초 256 MB 269967 79590 55961 27.478%

문제

M이상 N이하의 소수를 모두 출력하는 프로그램을 작성하시오.

입력

첫째 줄에 자연수 M과 N이 빈 칸을 사이에 두고 주어진다. (1 ≤ M ≤ N ≤ 1,000,000) M이상 N이하의 소수가 하나 이상 있는 입력만 주어진다.

출력

한 줄에 하나씩, 증가하는 순서대로 소수를 출력한다.

예제 입력 1 복사

3 16

예제 출력 1 복사

3
5
7
11
13

 

 

위 문제는 모든 가능한 수로 나눠보면서, 나머지를 확인하는 방법보다, 에라토스테네스의 체를 활용하여 배수들을 제거해나가는 방식으로 풀어야 시간제한 안에 풀린다.

https://ko.wikipedia.org/wiki/%EC%97%90%EB%9D%BC%ED%86%A0%EC%8A%A4%ED%85%8C%EB%84%A4%EC%8A%A4%EC%9D%98_%EC%B2%B4

 

에라토스테네스의 체 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. 에라토스테네스의 체 수학에서 에라토스테네스의 체는 소수를 찾는 빠르고 쉬운 방법이다. 고대 그리스 수학자 에라토스테네스가 발견하였다. 알고리즘[편집]

ko.wikipedia.org

 

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int arr[1000001]; //전역 변수 선언시 자동으로 0으로 초기화. 소수면 0, 아니면 1

void print_prime(int a, int b)
{
	
	//2,4,6,8 2(1,2,3,4,)  -> j (i) 
	//3,6,9,12 3(1,2,3,4,)
	arr[0] = 1;
	arr[1] = 1;
	
	for (int i = 2; i <= b; i++) {
		for (int j = 2 * i; j <= b; j += i) {
			if (arr[j] == 0) {
				arr[j] = 1; 
			}
		}
	}
	

	for (int i = a; i <= b; i++) {
		if (!arr[i])
			printf("%d\n", i);
	}
}

int main()
{
	int m, n;
	scanf("%d %d", &m, &n);

	print_prime(m, n);

	return 0;
}

'알고리즘 > 백준' 카테고리의 다른 글

[백준] 9012 괄호  (0) 2024.02.25
[백준] 2798 블랙잭  (1) 2024.02.25
[백준] 1920 수 찾기  (0) 2024.02.19
[백준] 1676 팩토리얼 0의 개수  (0) 2024.02.17
[백준] 1654 랜선 자르기  (0) 2024.02.16

수 찾기

 
시간 제한메모리 제한제출정답맞힌 사람정답 비율

 

1 초 128 MB 249191 76985 51061 29.991%

문제

N개의 정수 A[1], A[2], …, A[N]이 주어져 있을 때, 이 안에 X라는 정수가 존재하는지 알아내는 프로그램을 작성하시오.

입력

첫째 줄에 자연수 N(1 ≤ N ≤ 100,000)이 주어진다. 다음 줄에는 N개의 정수 A[1], A[2], …, A[N]이 주어진다. 다음 줄에는 M(1 ≤ M ≤ 100,000)이 주어진다. 다음 줄에는 M개의 수들이 주어지는데, 이 수들이 A안에 존재하는지 알아내면 된다. 모든 정수의 범위는 -231 보다 크거나 같고 231보다 작다.

출력

M개의 줄에 답을 출력한다. 존재하면 1을, 존재하지 않으면 0을 출력한다.

예제 입력 1 복사

5
4 1 5 2 3
5
1 3 7 9 5

예제 출력 1 복사

1
1
0
0
1

 

시간 제한이 1초인 문제이므로, A배열에서 수를 찾을때, 정렬 후 이진 탐색으로 찾아야 한다.

 

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

int previous_compare_int(const void* a, const void* b){
	return (*(int*)a-*(int*)b)
}

int compare_int(const void* a, const void* b) {
	int int_a = *(const int*)a;
	int int_b = *(const int*)b;

	if (int_a < int_b) return -1; 
	if (int_a > int_b) return 1;  
	return 0; 
}

//only if array1, array2 's size is same, and array1 is sorted
void check_and_print(int* array1, int* array2, int num_array1, int num_array2) {
	char flag = 0; //default is 0
	int left, right, middle, search_value;
	
	for (int i = 0; i < num_array2; i++) { //find array2's member in array1
		left = 0;
		right = num_array1 - 1;
		search_value = array2[i];

		//b-search
		while (left <= right) {
			middle = left + (right - left) / 2;
			if (array1[middle] > search_value) {
				right = middle - 1;
			}
			else if (array1[middle] < search_value) {
				left = middle + 1;
			}
			else if (array1[middle] == search_value){
				flag = 1;
				break;
			}
		}

		//here to print
		if (flag) {
			printf("1\n");
			flag = 0;
		}
		else {
			printf("0\n");
		}
	}
 }

int main() {
	int num_array1 = 0;
	int num_array2 = 0;
	int* array1 = NULL;
	int* array2 = NULL;


	scanf("%d", &num_array1);
	array1 = (int*)malloc(sizeof(int) * num_array1);
	for (int i = 0; i < num_array1; i++) {
		scanf("%d", &array1[i]);
	}

	scanf("%d", &num_array2);
	array2 = (int*)malloc(sizeof(int) * num_array2);
	for (int i = 0; i < num_array2; i++) {
		scanf("%d", &array2[i]);
	}
	
	qsort(array1, num_array1, sizeof(int), compare_int);
	

	check_and_print(array1, array2, num_array1, num_array2);
	
	free(array1);
	free(array2);

	return 0;
}

 

"previous_compare_int"는 초반에 작성한 함수로, 첫번째 인자가 큰 경우 양수, 같을경우 0, 두번째 인자가 클 경우 음수를 반환하게 설계하였지만, 입력의 최댓값이 2^31이므로 차를 구하는 과정에서 첫 인자가 2^31 - 1, 두번째 인자가 -1 이하긴 경우에 integer_overflow가 발생하므로 의도한대로 함수가 작동하지 않는다.

따라서, 대소 비교 후 +1, 0, -1을 반환하는 함수로 변경하였다.

'알고리즘 > 백준' 카테고리의 다른 글

[백준] 2798 블랙잭  (1) 2024.02.25
[백준] 1929 소수 구하기  (0) 2024.02.22
[백준] 1676 팩토리얼 0의 개수  (0) 2024.02.17
[백준] 1654 랜선 자르기  (0) 2024.02.16
[백준] 1181 단어 정렬  (1) 2024.02.09

팩토리얼 0의 개수

 
시간 제한메모리 제한제출정답맞힌 사람정답 비율
2 초 128 MB 77545 36650 30670 46.959%

문제

N!에서 뒤에서부터 처음 0이 아닌 숫자가 나올 때까지 0의 개수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 N이 주어진다. (0 ≤ N ≤ 500)

출력

첫째 줄에 구한 0의 개수를 출력한다.

예제 입력 1 복사

10

예제 출력 1 복사

2

예제 입력 2 복사

3

예제 출력 2 복사

0

 

 

문제 말이 이해하기 어려운데, 

N!에서 뒤에서부터 처음 0이 아닌 숫자가 나올 때 까지의 0의 개수를 구해라고 한다.

여기서 "처음 0이 아닌 숫자"라는 말은, 

예를 들어 2100이 있으면, "뒤에서부터"는 1의 자리수부터를 말하는 것이므로 처음 0이 아닌 수는 "1"을 말하는 것이다.

이때까지의 0의 개수를 구하라고 했으므로, 이 예제에서의 답은 "2"이다.

ex) 42340080000 -> 4

 

N 팩토리얼은 1부터 N까지 하나씩 전부 곱하는 연산이다. 또한, 뒷자리에 0이 오려면 10의 배수여야 한다. 10은 2와 5로 소인수분해 되므로, 소인수분해 했을때, 2의 개수와 5의 개수 중 가장 작은 값이 답이다. (2^5 * 5^6 -> 5)

하지만, 우리는 입력을 팩토리얼로 처리하고, 팩토리얼 연산은 1부터 하나하나 곱하기 때문에 소인수 분해시, 5의 개수가 2의 개수보다 더 많은 경우는 없다. 

따라서, 소인수 분해 시 5의 개수를 구하면 된다.

 

주의점으로, 입력 범위가 0~500이므로, 5^1, 5^2, 5^3 이 연산에 있을 수 있으므로, 해당 경우까지 고려해야 한다.

 

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
	int num;
	int check_five = 0;
	scanf("%d", &num);
	
	for (int i = 1; i <= num; i++) {
		if (!(i % 5)) {
			check_five++;
			if (!((i / 5) % 5)) {
				check_five++;
				if (!((i / 25) % 5)) {
					check_five++;
				}
			}
		}
			
	}
	printf("%d", check_five);
}

'알고리즘 > 백준' 카테고리의 다른 글

[백준] 1929 소수 구하기  (0) 2024.02.22
[백준] 1920 수 찾기  (0) 2024.02.19
[백준] 1654 랜선 자르기  (0) 2024.02.16
[백준] 1181 단어 정렬  (1) 2024.02.09
[백준] 1018 체스판 다시 칠하기  (4) 2024.01.03

랜선 자르기 

시간 제한            메모리 제한              제출                             정답                        맞힌 사람                정답 비율

 

2 초 128 MB 210053 49585 33532 21.280%

문제

집에서 시간을 보내던 오영식은 박성원의 부름을 받고 급히 달려왔다. 박성원이 캠프 때 쓸 N개의 랜선을 만들어야 하는데 너무 바빠서 영식이에게 도움을 청했다.

이미 오영식은 자체적으로 K개의 랜선을 가지고 있다. 그러나 K개의 랜선은 길이가 제각각이다. 박성원은 랜선을 모두 N개의 같은 길이의 랜선으로 만들고 싶었기 때문에 K개의 랜선을 잘라서 만들어야 한다. 예를 들어 300cm 짜리 랜선에서 140cm 짜리 랜선을 두 개 잘라내면 20cm는 버려야 한다. (이미 자른 랜선은 붙일 수 없다.)

편의를 위해 랜선을 자르거나 만들 때 손실되는 길이는 없다고 가정하며, 기존의 K개의 랜선으로 N개의 랜선을 만들 수 없는 경우는 없다고 가정하자. 그리고 자를 때는 항상 센티미터 단위로 정수길이만큼 자른다고 가정하자. N개보다 많이 만드는 것도 N개를 만드는 것에 포함된다. 이때 만들 수 있는 최대 랜선의 길이를 구하는 프로그램을 작성하시오.

입력

첫째 줄에는 오영식이 이미 가지고 있는 랜선의 개수 K, 그리고 필요한 랜선의 개수 N이 입력된다. K는 1이상 10,000이하의 정수이고, N은 1이상 1,000,000이하의 정수이다. 그리고 항상 K ≦ N 이다. 그 후 K줄에 걸쳐 이미 가지고 있는 각 랜선의 길이가 센티미터 단위의 정수로 입력된다. 랜선의 길이는 231-1보다 작거나 같은 자연수이다.

출력

첫째 줄에 N개를 만들 수 있는 랜선의 최대 길이를 센티미터 단위의 정수로 출력한다.

예제 입력 1 복사

4 11
802
743
457
539

예제 출력 1 복사

200

힌트

802cm 랜선에서 4개, 743cm 랜선에서 3개, 457cm 랜선에서 2개, 539cm 랜선에서 2개를 잘라내 모두 11개를 만들 수 있다

 

해당 문제의 알고리즘은, binary search이다.

이진 탐색은, 중간값을 매개변수에 넣어 조건을 확인하고, 조건보다 크다면 오른쪽 범위를, 작다면 왼쪽 범위를 생각하는 알고리즘이다. 

https://ko.wikipedia.org/wiki/%EC%9D%B4%EC%A7%84_%EA%B2%80%EC%83%89_%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98

 

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

int calculate(int* array, int num, int mid) {
	int sum = 0;
	for (int i = 0; i < num; i++) {
		sum += array[i] / mid;
	}
	return sum;
}
int loop(int* array, int num, int goal, int max) {
	long left = 1;
	int right = max;
	long mid;
	int value;

	while (left <= right) {
		mid = left + (right - left) / 2;
		if (calculate(array, num, mid) >= goal) {
			value = mid;
			left = mid + 1;
		}
		else {
			right = mid - 1;
		}
	}
	return value;
}
int main() {
	int num;
	int goal;

	scanf("%d", &num);
	scanf("%d", &goal);

	int* array = (int*)malloc(sizeof(int) * num);

	int max = 0;

	for (int i = 0; i < num; i++) {
		scanf("%d", &array[i]);
		if (max < array[i]) {
			max = array[i];
		}

	}

	printf("%d", loop(array, num, goal, max ));

	free(array);
	return 0;
}

 

주의할 점으로, loop함수의 left, mid 변수는 int 타입보다 큰 long으로 설정해줘야 한다.

위 코드상, mid 변수 또한 left + right 연산을 하지 않기 위해 (overflow 위험성) left + (right - left)와 같이 간격을 통한 연산으로 오류를 방지하려 했으나, while루프의 조건처럼 left == right == int_max인 경우, mid와 left 변수가 overflow가 발생한다. 

(left = mid + 1;부분에서) 따라서, mid, left 변수는 더 큰 long으로 할당하고, 오버플로 가능성이 없는 right는 int로 선언한다.

 

또한, 본래 알고리즘으론 입력값 타입의 최대값인 int_max를 사용하지만, 이 문제에선 가장 큰 선의 길이를 구하여 해당 길이를 가장 큰 값 (bst 범위 중 right값)으로 사용하여 조금의 효율성을 챙겼다.

 

'알고리즘 > 백준' 카테고리의 다른 글

[백준] 1929 소수 구하기  (0) 2024.02.22
[백준] 1920 수 찾기  (0) 2024.02.19
[백준] 1676 팩토리얼 0의 개수  (0) 2024.02.17
[백준] 1181 단어 정렬  (1) 2024.02.09
[백준] 1018 체스판 다시 칠하기  (4) 2024.01.03

단어 정렬

 시간제한         메모리제한                 제출                           정답                         맞힌사람               정답비율
2 초 256 MB 174784 73233 54897 40.354%

문제

 

알파벳 소문자로 이루어진 N개의 단어가 들어오면 아래와 같은 조건에 따라 정렬하는 프로그램을 작성하시오.

  1. 길이가 짧은 것부터
  2. 길이가 같으면 사전 순으로

단, 중복된 단어는 하나만 남기고 제거해야 한다.

 

입력

첫째 줄에 단어의 개수 N이 주어진다. (1 ≤ N ≤ 20,000) 둘째 줄부터 N개의 줄에 걸쳐 알파벳 소문자로 이루어진 단어가 한 줄에 하나씩 주어진다. 주어지는 문자열의 길이는 50을 넘지 않는다.

 

출력

조건에 따라 정렬하여 단어들을 출력한다.

예제 입력 1 

13
but
i
wont
hesitate
no
more
no
more
it
cannot
wait
im
yours

예제 출력 1 

i
im
it
no
but
more
wait
wont
yours
cannot
hesitate
 
 

 

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


int main(int argc, char* argv[]) {
	int input_count = 0;
	scanf("%d", &input_count);
	char** input_string = (char**)malloc(sizeof(char*) * input_count);
	char buffer[51] = { 0 }, temp[51] = { 0 };
	while (getchar() != '\n'); //엔터키 잡기

	for (int i = 0; i < input_count; i++) {
		fgets(buffer, sizeof(buffer), stdin);
		
		buffer[strcspn(buffer, "\n")] = '\0';
		input_string[i] = (char*)malloc(sizeof(char) * 51); 
		strcpy(input_string[i], buffer);
		fflush(stdin);
	}
	
	for (int i = 0; i < input_count - 1; i++) {
		for (int j = 0; j < input_count - 1 - i; j++) {
			if (strlen(input_string[j]) > strlen(input_string[j + 1])) {
				strcpy(temp, input_string[j + 1]);
				strcpy(input_string[j + 1], input_string[j]);
				strcpy(input_string[j], temp);
			}
		}
	}
	
	for (int i = 0; i < input_count - 1; i++) {
		if (strcmp(input_string[i], input_string[i + 1]) == 0) {
			free(input_string[i]);
			for (int j = i; j < input_count - 1; j++) {
				input_string[j] = input_string[j + 1];
			}
			input_count--;
			i--;
		}
	}
	for (int i = 0; i < input_count - 1; i++) {
		for (int j = 0; j < input_count - 1 - i; j++) {
			if (strlen(input_string[j]) == strlen(input_string[j + 1])) {
				if (strcmp(input_string[j], input_string[j + 1]) > 0) {
					strcpy(temp, input_string[j + 1]);
					strcpy(input_string[j + 1], input_string[j]);
					strcpy(input_string[j], temp);
				}
			}
		}
	}
	for (int i = 0; i < input_count; i++) {
		printf("%s\n", input_string[i]);
	}

	for (int i = 0; i < input_count; i++)
		free(input_string[i]);
	free(input_string);

	return 0;
}

 

본래 작성한 코드로, 로직 흐름을 보면

1. 입력한 "입력 수"에 따라 최대 문자 길이 '50'에 null값까지 포함한 51 byte의 크기를 가지는 배열 생성.

-> 공간 비효율적 

 

2. 문자열 길이대로 bubble 정렬, 이후에 사전순 bubble 정렬

-> 시간 복잡도가 O(n^2) + O(n^2)으로 매우 비효율적

 

3. 2중 for문 내에서 strcpy를 3번이나 호출함

 -> 매우매우 비효율적

 

4. 공간이 넉넉하다면, 굳이 겹치는 원소를 free해줄 필요가 없다. 불필요한 쓰기 행위일 수 있음

-> 이전 원소와 비교하여 같지 않은 원소만 출력하는 방향으로 수정할 수 있다.

 

결과 :

 

매우 비효율적인 프로그램으로 시간 초과 오답이다.

 

해당 문제의 정답 코드를 보면, 

#include <iostream>
#include <algorithm>
using namespace std;

int cmp(string a, string b) {
	// 1. 길이가 같다면, 사전순으로
	if (a.length() == b.length()) {
		return a < b;
	}
	// 2. 길이가 다르다면, 짧은 순으로 
	else {
		return a.length() < b.length();
	}
}

// 범위가 크기때문에 전역변수로 설정
string word[20000];

int main() {
int main() {
	int N;

	cin >> N;
	for (int i = 0; i < N; i++) {
		cin >> word[i];
	}

	sort(word, word + N, cmp);

	for (int i = 0; i < N; i++) {
		// 중복된 경우 한번만 출력
		if (word[i] == word[i - 1]) {
			continue;
		}
		cout << word[i] << "\n";
	}

	return 0;
}

 

C++의 standard library를 사용하여 간단하게 풀 수 있다.

 

이러한 문제를 "STL 코딩" 문제라 부르며, Standard Library를 잘 활용하는 능력을 확인한다.

 

버블정렬은 비효율적이며, 힙 퀵 병합 정렬을 사용하면 시간이 줄어들것이라 예상할 수 있다.

 

 

 

C로 풀고싶지만 stl로 출제 의도를 생각하고 넘어가겠다..

 

 

'알고리즘 > 백준' 카테고리의 다른 글

[백준] 1929 소수 구하기  (0) 2024.02.22
[백준] 1920 수 찾기  (0) 2024.02.19
[백준] 1676 팩토리얼 0의 개수  (0) 2024.02.17
[백준] 1654 랜선 자르기  (0) 2024.02.16
[백준] 1018 체스판 다시 칠하기  (4) 2024.01.03

문제

지민이는 자신의 저택에서 MN개의 단위 정사각형으로 나누어져 있는 M×N 크기의 보드를 찾았다. 어떤 정사각형은 검은색으로 칠해져 있고, 나머지는 흰색으로 칠해져 있다. 지민이는 이 보드를 잘라서 8×8 크기의 체스판으로 만들려고 한다.

체스판은 검은색과 흰색이 번갈아서 칠해져 있어야 한다. 구체적으로, 각 칸이 검은색과 흰색 중 하나로 색칠되어 있고, 변을 공유하는 두 개의 사각형은 다른 색으로 칠해져 있어야 한다. 따라서 이 정의를 따르면 체스판을 색칠하는 경우는 두 가지뿐이다. 하나는 맨 왼쪽 위 칸이 흰색인 경우, 하나는 검은색인 경우이다.

보드가 체스판처럼 칠해져 있다는 보장이 없어서, 지민이는 8×8 크기의 체스판으로 잘라낸 후에 몇 개의 정사각형을 다시 칠해야겠다고 생각했다. 당연히 8*8 크기는 아무데서나 골라도 된다. 지민이가 다시 칠해야 하는 정사각형의 최소 개수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 N과 M이 주어진다. N과 M은 8보다 크거나 같고, 50보다 작거나 같은 자연수이다. 둘째 줄부터 N개의 줄에는 보드의 각 행의 상태가 주어진다. B는 검은색이며, W는 흰색이다.

출력

첫째 줄에 지민이가 다시 칠해야 하는 정사각형 개수의 최솟값을 출력한다.

 

예제 입력 1 

8 8
WBWBWBWB
BWBWBWBW
WBWBWBWB
BWBBBWBW
WBWBWBWB
BWBWBWBW
WBWBWBWB
BWBWBWBW

예제 출력 1 

 

1

예제 입력 2 

10 13
BBBBBBBBWBWBW
BBBBBBBBBWBWB
BBBBBBBBWBWBW
BBBBBBBBBWBWB
BBBBBBBBWBWBW
BBBBBBBBBWBWB
BBBBBBBBWBWBW
BBBBBBBBBWBWB
WWWWWWWWWWBWB
WWWWWWWWWWBWB

예제 출력 2 

12

 

예제 입력 3 

8 8
BWBWBWBW
WBWBWBWB
BWBWBWBW
WBWBWBWB
BWBWBWBW
WBWBWBWB
BWBWBWBW
WBWBWBWB

예제 출력 3 

0

예제 입력 4 

9 23
BBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBW

예제 출력 4 

31

예제 입력 5 

10 10
BBBBBBBBBB
BBWBWBWBWB
BWBWBWBWBB
BBWBWBWBWB
BWBWBWBWBB
BBWBWBWBWB
BWBWBWBWBB
BBWBWBWBWB
BWBWBWBWBB
BBBBBBBBBB

예제 출력 5 

0

 

예제 입력 6 

8 8
WBWBWBWB
BWBWBWBW
WBWBWBWB
BWBBBWBW
WBWBWBWB
BWBWBWBW
WBWBWWWB
BWBWBWBW

예제 출력 6 

2

예제 입력 7 

11 12
BWWBWWBWWBWW
BWWBWBBWWBWW
WBWWBWBBWWBW
BWWBWBBWWBWW
WBWWBWBBWWBW
BWWBWBBWWBWW
WBWWBWBBWWBW
BWWBWBWWWBWW
WBWWBWBBWWBW
BWWBWBBWWBWW
WBWWBWBBWWBW

예제 출력 7 

15

 

 

 

 

이 문제는 브루트포싱을 주제로 하는 문제이다.

최적의 경우를 구하는 문제이고, 해당 문제에 적합한 알고리즘이 생각나지 않으므로 브루트포싱이 접근하는데에 있어서 가장 먼저 시도해야 할 알고리즘일 것이다.

 

우선 생각해야 할 점은, 

 

N X M 행열이 주어졌을때,

1.여러개의 8x8 행렬로 나눈다.

2.선택한 8x8 행렬에 대한 문제에서 제시하는 경우의 수를 구한다.

3.모든 행렬에 대한 경우의 수를 비교하여 최적의 경우를 출력한다.

 

현재 정사각행렬인 8x8 행렬을 사용하므로, 행과 열을 같은 간격의 index로 접근하되, spacial locality만 고려해주면 된다.

 

사용자가 행과 열의 값을 N 과 M으로 입력했을때, 

이차원 배열의 행 인덱스는

0 1 2 ... n-8 n-7 n-6 n-5 n-4 n-3 n-2 n-1,

열 인덱스도 마찬가지로  

0 1 2 ... m-8 m-7 m-6 m-5 m-4 m-3 m-2 m-1

와 같은 형태로 접근할 수 있다.

 

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
//#include <climits> (use if your compiler need it)


int getCases(int row, int col, char **input) {
	int countW = 0;
	int countB = 0;
	// case W
	for (int i = row; i < row + 8 - 1; i+=2) {
		//first row
		for (int j = col; j < col + 8 - 1; j+=2) {
			if (input[i][j] == 'B') {
				//input[i][j] = 'W';
				countW++;
				if (input[i][j + 1] == 'W') {
					//input[i][j + 1] = 'B';
					countW++;
				} 
			}
			else {
				if (input[i][j + 1] == 'W') {
					//input[i][j + 1] = 'B';
					countW++;
				}
			}
		}
		//second row
		for (int j = col; j < col + 8 - 1; j += 2) {
			if (input[i+1][j] == 'W') {
				//input[i+1][j] = 'B';
				countW++;
				if (input[i+1][j + 1] == 'B') {
					//input[i+1][j + 1] = 'W';
					countW++;
				}
			}
			else {
				if (input[i+1][j + 1] == 'B') {
					//input[i+1][j + 1] = 'W';
					countW++;
				}
			}
		}
	}
	// case B
	for (int i = row; i < row + 8 - 1; i += 2) {
		//first row
		for (int j = col; j < col + 8 - 1; j += 2) {
			if (input[i][j] == 'W') {
				//input[i][j] = 'B';
				countB++;
				if (input[i][j + 1] == 'B') {
					//input[i][j + 1] = 'W';
					countB++;
				}
			}
			else {
				if (input[i][j + 1] == 'B') {
					//input[i][j + 1] = 'W';
					countB++;
				}
			}
		}
		//second row
		for (int j = col; j < col + 8 - 1; j += 2) {
			if (input[i + 1][j] == 'B') {
				//input[i + 1][j] = 'W';
				countB++;
				if (input[i + 1][j + 1] == 'W') {
					//input[i + 1][j + 1] = 'B';
					countB++;
				}
			}
			else {
				if (input[i + 1][j + 1] == 'W') {
					//input[i + 1][j + 1] = 'B';
					countB++;
				}
			}
		}
	}
	return countW < countB ? countW : countB;
}

int main(int argc, char* argv[]) {
	int row, col, temp;
	int min = INT_MAX;
	char** input;
	char ch;

	//user input
	scanf("%d %d ", &row, &col);

	//space allocate
	input = (char**)malloc(sizeof(char*) * row);
	for (int i = 0; i < row; i++) {
		input[i] = (char*)malloc(sizeof(char) * col);
	}
	
	//input value
	for (int i = 0; i < row; i++) {
		for (int j = 0; j < col; j++) {
			ch = getchar();
			if (ch == '\n') {
				ch = getchar();
			}
			input[i][j] = ch;
		}
	}
	
	//func
	for (int i = 0; i <= row - 8; i++) {
		for (int j = 0; j <= col - 8; j++) {
			temp = getCases(i, j, input);
			if (temp < min)
				min = temp;
		}
	}
	printf("%d", min);
    
    	for (int i = 0; i < row; i++) {
		free(input[i]);
	}
	free(input);
    
	return 0;
}

 

 

 

메모리 접근만 신경쓰면 쉽게 해결된다.

'알고리즘 > 백준' 카테고리의 다른 글

[백준] 1929 소수 구하기  (0) 2024.02.22
[백준] 1920 수 찾기  (0) 2024.02.19
[백준] 1676 팩토리얼 0의 개수  (0) 2024.02.17
[백준] 1654 랜선 자르기  (0) 2024.02.16
[백준] 1181 단어 정렬  (1) 2024.02.09

+ Recent posts