PS/자주 하는 답변

예제가 반례입니다.

djm03178 2022. 12. 30. 16:47

문제를 풀다가 '틀렸습니다'가 나오면 대부분의 사람들은 매우 답답할 것입니다. 아무리 봐도 맞는 코드인데, 예제는 맞고, 어디 반례가 없을까 찾게 되는 것이 매우 일반적입니다.

 

하지만 놀라운 사실이 있습니다. 반례를 찾는 질문들 중 상당히 높은 비율에서 예제가 반례로 나타난다는 것입니다. 예제를 테스트 해보는 것은 기본이기에 단순히 깜빡하고 안 해본 예제가 있어서인 경우는 사실 그렇게 많지는 않습니다. 대개는 예제를 해보고도 그게 반례라는 것을 깨닫지 못하는 경우입니다. 자주 보이는 사례들을 정리해 보았습니다.

  • 출력이 100% 일치하지 않는 경우: 채점 프로그램은 출력하는 한 글자 한 글자에 매우 민감합니다. 출력은 언제나 요구한 것을 글자 단위로 정확하게 출력해야 합니다 (일부 예외 제외).
    • 수를 공백으로 구분하여 출력하라고 했으면 정확하게 공백으로 구분하여 출력을 해줘야 하고, 수가 붙어서 나온다거나, 두 칸씩 떨어져 있다거나, 매 줄의 시작에 불필요한 공백이 출력된다거나 하는 등은 모두 오답입니다.
    • 23 45를 출력해야 하는데 2345, 23     45,23:45, 23/45, 23시 45분 등을 출력한다거나 하는 것 모두 오답입니다. (일부는 '출력 형식이 잘못되었습니다'를 받게 됩니다.)
    • 40.000%를 출력해야 하는데 40%, 40.0%, 40.000, 40, 40퍼센트 등을 출력해도 모두 오답입니다.
    • [1,2]처럼 공백 없이 출력해야 하는데 [1, 2]와 같이 공백이 사이에 들어가도 안 됩니다. (Python의 list를 그대로 출력하셨나요?)
    • 입력을 받는 과정에서 "시간을 입력하세요:"와 같은 문구를 출력해서도 안 됩니다. 모든 출력은 반드시 정답에 해당하는 것만 이루어져야 합니다.
    • 테스트 케이스마다 정답을 하나씩 출력해야 하는 경우 반드시 매 케이스마다 개행 문자를 출력해야 합니다.
    • 널 문자('\0', 0의 값을 가지는 char)를 출력해서는 안 됩니다. 널 문자는 환경에 따라서 아무것도 출력되지 않거나 공백 문자처럼 출력되기 때문에 눈에 보이지 않을 수 있지만, 널 문자도 엄연히 하나의 문자이며 널 문자의 출력을 요구하는 문제는 단 하나도 존재하지 않습니다. 널 문자가 출력되면 무조건 오답이 됩니다.
    • 대문자로 출력하도록 되어있다면 대문자로 출력해야 합니다. 소문자로 출력하면 안 됩니다. Yes로 출력하라고 했으면 Yes로 출력해야 하고, yes, YES, yES, 등은 모두 오답입니다.
  • 코드에 수정한 곳이 있는데, 정답에 영향이 없을 거라고 생각해서 모든 예제를 다시 다 테스트 해보지 않는 경우: 코드는 처음부터 끝까지 전체가 유기적으로 연결되어 있습니다. 따라서 전혀 상관 없어 보이는 곳을 고친다고 하더라도, 그것이 아무리 사소해 보이더라도, 고친 것이 단 한 글자라고 하더라도 그것이 정답에 영향을 줄 수 있음을 인지해야 합니다. 살짝이라도 고친 곳이 있다면 반드시 모든 예제를 전부 다시 테스트 해보아야 합니다. 특정 예제 하나가 안 나와서 그걸 위한 예외 처리를 추가한 것이라고 하더라도 나머지 예제를 다시 다 해보아야 합니다.
  • 코드에 undefined behavior가 있는 경우: C/C++에서는 매우 흔한 경우입니다. Undefined behavior가 있으면 아무리 어떤 입력을 넣어봐도 항상 잘 나오는 것처럼 보일 수 있으나, 다른 환경에서는 아무 입력이나, 예제 1번만 넣어도 항상 반례가 될 수도 있습니다. 이는 단순히 반례를 찾는 것 외에도 눈으로 코드를 읽으면서 검증하는 능력도 키워야 한다는 것을 의미합니다. 컴파일러 경고를 꼼꼼히 읽는 습관을 들이는 것도 도움이 됩니다. Undefined behavior에 대해서는 이 글을 참고하세요.
  • 특정 환경에서만 동작하는 기능을 사용한 경우: 대표적인 것이 C에서 fflush(stdin), rewind(stdin) 등을 이용해 입력 버퍼를 비우려는 경우, strcmp 함수가 무조건 -1, 0, 1 중 하나를 반환하는 것으로 가정하는 경우 (표준상으로는 음의 정수, 0, 양의 정수인 것만 보장됩니다), Java에서 Scanner나 BufferedReader를 여러 개 만들어서 입력받으려는 경우 등입니다. 이외에도 표준에 명시되지 않은 방식으로 특정 라이브러리에서만 지원해주는 것들을 채점 환경에서도 똑같이 동작할 거라고 생각하면 안 되고, 항상 https://en.cppreference.com/w/ 등을 통해 레퍼런스에서 명시한 내용을 따르도록 하는 것이 좋습니다.
  • Python에서 인터랙터가 보여주는 값은 출력이 아닙니다. 출력은 반드시 print 또는 sys.stdout.write를 통해 해야 합니다. 그냥 변수나 함수 호출 문장만 적었을 뿐인데 화면에 출력이 나오는 건 인터랙터가 그 값을 보여주도록 되어있기 때문이고, 이는 문제에서 요구하는 출력 방법이 아닙니다.
  • 정답 출력 후 프로그램이 정상적으로 종료가 되었나요? 프로그램은 반드시 정답 출력 후 정상적으로 종료가 되어야 합니다. EOF까지 입력을 받아야 하는 문제 등에서 무한 루프를 돌면서 입력만 받고 정답이 출력되는 것까지만 확인한 뒤 예제가 나왔다고 생각하는 경우를 많이 볼 수 있습니다. 무한 루프를 계속 돈다거나, 예외가 발생해서 비정상적으로 프로그램이 종료된다거나 하는 일이 있어서는 안 됩니다. 또한 정상 종료라는 것은 프로그램의 exit code가 0이어야 한다는 뜻으로, exit()에 0이 아닌 값을 넣어서 종료했거나, main 함수가 0이 아닌 값을 반환한 것은 모두 비정상 종료입니다. 반드시 프로그램이 정상적으로 종료되는지까지 확인하세요.

 

반례 찾아 삼만 리를 떠나기 전에, 눈앞에 펼쳐진 예제들부터 먼저 확실하게 되는지, 다시 한 번 확인해보고 가는 건 어떨까요?

 

 

매 케이스마다 개행 문자를 출력해야 합니다.

다중 테스트 케이스 문제들에서 조심해야 할 것은, 단일 테스트 케이스 문제와 달리 답을 하나만 딱 출력하고 끝내면 안 된다는 것입니다. 채점 프로그램은 그저 출력한 내용 전체가 정답 전체

djm03178.tistory.com