1541 : 잃어버린 괄호

네르기·2021년 8월 10일
0

알고리즘

목록 보기
7/76

뭐하는 문제인가?

괄호를 적절히 씌워서 주어진 식의 최솟값을 구하는 문제다.

여보시어요

내가 생각한 의사 코드는 다음과 같았다.

Declare N = [], O = [], S = 0, i = 0. sub = false
Get S
while S[i] != '\0':
    if S[i] == '+' or S[i] == '-':
        partition S from i to j as a number n.
        j = i+1
        append number n to N.
        append S[i] to O.
S = N[0]
For i=0 to (length of O):
    if O[i] == '-':
        sub = !sub;
    if sub:
        S -= N[i+1]
    else:
        S += N[i+1]
print S
  • 입력을 통으로 받고 거기에서 숫자와 연산자를 나눈다.
  • 식의 부호 상태에 따라 더하기 혹은 빼기를 해서 최소값이 나오도록 한다.

어지럽네요

최종적으로 완성된 내 코드다.

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

int p(char* s, int st, int en) {
    int i=0, m=0, r;
    char* ss = (char*)calloc(en-st, sizeof(char));
    for(i=st;i<en;i++)
        ss[m++] = s[i];
    r = atoi(ss);
    free(ss);
    return r;
}

int main() {
    char S[51]={0}, O[24]={0};
    int N[25]={0}, sub=0, s=0, i=0, j=0, k=0, l=0;
    scanf("%s", S);
    while(S[i]!=0) {
        if(S[i]=='+' || S[i]=='-') {
            N[k++] = p(S, j, i);
            O[l++] = S[i];
            j = i+1;
        }
        i++;
    }
    N[k++] = p(S, j, i);
    s = N[0];
    for(i=0;i<l;i++) {
        if(O[i]=='-') {
            sub = 1;
            s -= N[i+1];
        } else if(O[i] == '+') {
            if(sub) s -= N[i+1];
            else s += N[i+1];
        }
    }
    printf("%d", s);
}

그저 더럽다. 또한 몇가지 시행착오가 있었다.

  1. 1-3-5-2-3 = ?
    -> sub의 상태에 따라 +나 -의 작동 방식이 달랐는데, 처음에는 -가 나타날 때마다 sub 값을 전환시키고, sub가 참이면 빼고 거짓이면 더하다 보니 틀렸다.

  2. 1-3+5-2+3 = ?
    -> 1.의 실수를 바로잡았지만 이번에는 sub가 참이고 +가 나오면 빼는 구문을 넣지 않아 틀렸다.

  3. malloc v. calloc
    -> 의외의 복병으로, 이것 때문에 문자열과 숫자열을 나누는 함수에서 결과값이 이상하게 나왔었다. 예컨대 50+1을 하면 50+10이 나왔다. 결론은 연속된 데이터를 표현할거면 calloc을 써라.

다른 사람은 어떻게 했는가?

#include <stdio.h>
#include <stdlib.h>
int main()
{
	int n, result = 0;
	char c;
	while(scanf("%d", &n) == 1){
		result += n;
		c = getchar();
		if(c == '-')
			break;
	}
	while(scanf("%d", &n) == 1){
		result -= n;
		c = getchar();
	}
	printf("%d\n", result);
}

my0421kr님의 소스
-> https://www.acmicpc.net/source/17238597

얼마나 간결한 소스인가!

내 바보같은 머리로 문제의 본질을 이해하는 데 꽤나 시간이 걸렸다. 결국 - 기호가 한번이라도 나오면 그 뒤에 있는 숫자 식은 전부 빼면 그만인 것을, 너무 복잡하게 생각했었다. 🤔

또한 통으로 받지 않아도 됐었다. scanf의 동작 방식을 생각했다면 위처럼 더 간략하게 줄일 수 있었는데, 그 당시에 나는 scanf("%d", &N) 해도 N에 숫자 말고 별거 들어갈 줄 알고 저렇게 안했다. 그러니 코드가 저렇게 길어지지.
-> https://www.ibm.com/docs/ko/i/7.3?topic=functions-scanf-read-data

stdin의 문자가 format-string와 충돌하면, scanf()가 종료됩니다. 충돌되는 문자는 읽히지 않은 것처럼 stdin의 왼쪽에 있습니다.

ㅋㅋ.. 이걸 이제야 알았다니.

느낀 점

실버 2짜리 문제가 왜 이렇게 어렵게 느껴지나 했더니 내 접근 방식이 좀 어려워서 그랬나 보다. 문제 풀어도 뻘짓한 것 같아서 기분이 좀 그렇다.

그리고 malloc이랑 calloc이랑 구분해서 써야겠다. 무지성으로 쓰더니 결국 일이 났네.

profile
프로그래머와 애니메이터가 되고파

0개의 댓글