본문 바로가기

Coding Tests/백준 온라인

( C ) 백준온라인 8958번

<문제>

https://www.acmicpc.net/problem/8958

 

8958번: OX퀴즈

"OOXXOXXOOO"와 같은 OX퀴즈의 결과가 있다. O는 문제를 맞은 것이고, X는 문제를 틀린 것이다. 문제를 맞은 경우 그 문제의 점수는 그 문제까지 연속된 O의 개수가 된다. 예를 들어, 10번 문제의 점수

www.acmicpc.net

 

<문제 접근>

N개의 문자열에따른 결과값들을 출력을 해야 한다. 크게 보면 2가지부분을 고려해야 하는데, 문자열N개를 입력을 받아야 한다는 것과, 그 문자열에 따른 결과값을 조건에 맞게 출력을 할 수 있게끔 구현해야 한다는 것이다. 


 

<잘못된 접근의 예>

우리가 문자열 N개를 입력받아야 한다면 어떻게 해야할까? 문자열 2개, 3개 등 갯수가 정해져 있다면 그 갯수에 맞게끔

문자열 배열을 2개 , 3개 만들어 줄 수도 있다. 그렇지만 N이 얼마의 수인지도 모를 뿐더러, N개 만큼 문자열배열을 생성할 수도 없는 노릇이다. 또 문자가 아닌 문자열들을 하나의 문자열 배열의 각 요소(인덱스)들에 집어 넣을 수도 없다. 이것은 완전히 잘못된 생각이다. 문자열은 우리가 알다시피 문자들과 널문자로 구성이 되어있다. 그렇기에 문자열의 구성적인 측면을 이해하면 위 생각이 잘못됬다는것을 깨달을 수 있다.

 

<예시>

#include <stdio.h>
int main(void)
{
	int test;
	scanf("%d", &test);
	char arr[80];
	for (int i = 0; i < test; i++) {
		scanf("%s", arr[i]);
	}
	printf("%s", &arr[0]);
	return 0;
}

위에서 얘기했던 대로 하나의 문자열안에 문자열을 배열요소값으로 넣으려고 하고 있다. 입력도 한 문장밖에 되지 않을 뿐더러 출력도 되지 않는다. 즉 올바르지 않다.

 


<조금 부족한 정답>

#include <stdio.h>
int main(void)
{
	int num;
	scanf("%d", &num);
	char arr[80];
	int k = 0;
	int sum = 0;
	for (int j = 0; j < num; j++) {
		scanf("%s", arr);
		for (int i = 0; arr[i] != 0; i++) {
			if (arr[i] == 'O') {
				++k;
				sum += k;
				continue;
			}
			if (arr[i] == 'X') {
				k = 0;
				continue;
			}
		}
		printf("%d\n", sum);
		for (int i = 0; arr[i] != 0; i++) {
			arr[i] = 0;
			k = 0;
			sum = 0;
	}
	}
}

처음 문자열 5개를 입력받아야 한다고 생각할때, 문자열의 특성, 개념을 잘 떠올리지 못하고 위의 코드 마지막 for문에서 보다시피 문자열을 0값 ,널값으로 초기화를 시켜주었다. 그랬던 이유는 이미 첫번째 문자열에따른 연산을 하였고 두번째 문자열 연산을 할때 그  전 문자열이 남아있는 것을 고려해 원래의 상태, 아무것도 입력되어 있지 않은것과 같은 상태로 초기화를 시켜주어야 한다고 생각 했기 때문이다.  그렇지만 밑의 예시를 통해 볼 수 있듯이...

 

<예시> positive, Love, red 를 입력해보자.

#include <stdio.h>
int main(void)
{
	char arr[10];
	for (int i = 0; i < 3; i++) {
		scanf("%s", arr);
		printf("%s\n", arr);
	}
}

문자열은 해당요소의 값의 변경이 가능하다. 우리가 scanf를 통해 문자열을 입력받을 때에도 이 문자열의 끝에는 널문자가 포함되어있다. 그런데 이 널문자는 앞서 말했듯이 문자열의 끝에 널문자가 삽입되어있는것이다. 하나의 문자열이 있으면 문자열 중간에 널문자를 삽입해서 문자열의 끝을 변경해 출력을 해보면, 이 변경된 끝을 기준으로 해서 출력이 된다.  그리고  문자열은 배열에 담겨있으니까 문자열의 일부를 변경하는것도 가능하다.

 

그러므로 문제에서 5개의 문자열을 입력받고 그에해당하는 sum값을 출력해야하는데, 5개의 문자열을 각각 담을 문자열 배열 5개가 필요한것도 아니고, sum을 출력할때 마다 다시 문자열 배열의 값을 널 값으로 초기화 해줄 필요도 없는것이다. 왜냐하면 새로운 문자열을 입력받게 되면, 다시금 그 입력된 문자열에 맟춰 문자열이 변경될 것이기 때문이다. 

 

<정답코드>

#include <stdio.h>
int main(void)
{
	int num;
	scanf("%d", &num);
	char arr[80];
	int k = 0;
	int sum = 0;
	for (int j = 0; j < num; j++) {
		scanf("%s", arr);
		for (int i = 0; arr[i] != 0; i++) {
			if (arr[i] == 'O') {
				++k;
				sum += k;
				continue;
			}
			if (arr[i] == 'X') {
				k = 0;
				continue;
			}
		}
		printf("%d\n", sum);
		sum = 0;
		k = 0;
	}
}

 

<continue문의 존재 이유> 문제에 상관없이 continue문을 사용한 이유를 알기 위해 작성해보았습니다. 

#include <stdio.h>
int main(void)
{
	int num;
	scanf("%d", &num);
	char arr[80];
	int k = 0;
	int sum = 0;
	for (int j = 0; j < num; j++) {
		scanf("%s", arr);
		for (int i = 0; arr[i] != 0; i++) {
			if (arr[i] == 'O') {
				++k;
				sum += k;
			}
			if (arr[i] == 'X') {
				k = 0;
			}
			printf("%d\n", sum);

		}

	}
}

continue문이 없다면 문자열 하나를 입력하면, 그 문자열의 문자 갯수에 맞춰 sum값이 출력이 되는것을 볼 수 있습니다. 그러므로 해당 if 블록을 실행하면 다음 조건으로 넘어갈 수 있게끔 continue문을 사용해 주어야 합니다.

 

<참고>

char arr [ ] = {'a', 'p', 'p', 'l', 'e', '\0'}의 문장이 있다 하면, 이는 널문자가 있기 때문에 문자 배열이 아닌 문자열이 저장된 배열(문자열)이라 할 수 있고, 이 문자열 즉 배열의 길이는 6이고, 문자열의 길이는 apple 즉 5이다. 널 문자가 문자열인지 아닌지 가리는 요소가 되지만,문자열의 길이에는  관여되지 않는다. 배열의 길이에 관여가 된다.