History: 알고스팟 온라인 저지/첫 번째 문제 풀기

어서 와 온라인 저지는 처음이지?

왼쪽 메뉴의 온라인 저지/문제 풀기를 클릭하면 문제 목록을 볼 수 있다. 문제 목록에서는 각 문제를 출처별/분류별/출제자별로 필터링해 볼 수 있다.

입출력을 테스트하기 위해, 가장 간단한 HELLOWORLD 문제를 풀어보자.

입출력

온라인 저지에서 프로그램은 모두 표준 입력 (standard input) 에서 입력을 읽어들이고, 표준 출력 (standard output) 으로 출력을 보낸다. Wikipedia에서 표준 입출력이 무엇인가에 대한 설명을 읽을 수 있다. C 로 말하자면 scanf/printf 를 쓰고, C++ 에서는 cin/cout, Java 에서는 System.inSystem.out 을 쓴다.

정답 기준

제출된 프로그램은, 채점 입력에 대한 계산 결과가 정확하게 정답과 일치해야만 정답으로 인정된다. 따라서 프로그램의 출력은 정확하게 문제에 명시된 대로여야 하며, 덜 출력해도 더 출력해도 안 된다. 답만 출력하는 대신 'The answer is X', 'Enter N' 등의 메시지를 출력하는 것은 전부 오답으로 처리된다.

생각해 보자. 채점을 사람이 하는 게 아닌 이상 프로그램이 출력한 메세지가 입력을 요구하는 것인지 아니면 답을 출력한 것인지 어떻게 안단 말인가?

테스트 케이스

온라인 저지에서는 항상 여러 개의 입력에 대해 프로그램을 실행해 보고 모든 답이 맞게 나오는 경우에만 정답으로 인정하게 된다. 입력을 바꿔 가며 프로그램을 여러 번 실행해도 되지만, 대개는 프로그램은 한 번만 실행하되, 입력 파일에서 여러 개의 입력을 주는 방식을 택한다.

이 문제에서도 인사할 사람의 이름이 첫 줄에 주어진다고 되어 있다.

한 가지 프로그래밍 대회를 처음 접하는 사람들이 흔히 하는 실수는, 한 번에 입력을 다 읽어들여 저장한 뒤 답을 계산하고 한번에 출력하는 것이다. 온라인 저지는 모든 출력을 한 번에 모아서 정답 여부를 판정하기 때문에, 한 번에 한 개의 예제를 읽어들여, 답을 구하고 출력하는 것을 반복해도 괜찮다. 물론 모든 입력을 받아 모아서 계산한 뒤 한꺼번에 출력해도 무방하지만, 구현의 편의를 위해서는 각 입력을 바로 처리하는 것이 현명하다.

다시 말하자면 표준입출력을 redirection하여 채점한다. 입력을 한 줄씩, 한 케이스씩 사람이 입력하고 결과를 채점하는 것이 아니다.

각 언어로 짜 본 HELLOWORLD 문제

Python

import sys
rl = lambda: sys.stdin.readline()
n = int(rl())
for i in range(n):
  print "Hello, %s!" % rl().strip()

C

#include<stdio.h>
int main() {
    int cases;
    char name[1024];
    scanf("%d", &cases);
    while(cases--) {
        scanf("%s", name);
        printf("Hello, %s!\n", name);
    }
}

C++

#include<iostream>
#include<string>
using namespace std;
int main() {
  int cases;
  cin >> cases;
  while(cases--) {
    string name;
    cin >> name;
    cout << "Hello, " << name << "!" << endl;     
  }
}

Java

Java의 경우에는, main 메소드가 있는 클래스명은 항상 Main 이어야 한다. 또한, 패키지를 지정해서는 안 된다.

// package helloworld; << DON'T

import java.util.HashMap;
import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int cases = sc.nextInt();
        while(cases-- > 0) {
            String name = sc.next();
            System.out.println("Hello, " + name + "!");
        }
    }
}

Haskell

하스켈의 경우에도, 모듈의 이름은 항상 Main 이어야 한다.

module Main where

main :: IO ()
main = do
  getLine
  interact (unlines . map hello . lines)

hello :: String -> String    
hello = ("Hello, " ++) . (++ "!")

Scala

스칼라의 경우에도, main() 함수가 있는 오브젝트의 이름은 항상 Main 이어야 한다.

object Main {
  def main(args: Array[String]): Unit = {
    var cases = Integer.parseInt(readLine())
    while (cases > 0) {
      println("Hello, " + readLine() + "!")
      cases -= 1
    }
  }
}

Ruby

루비 하앍하앍

Integer(gets).times { puts "Hello, #{gets.strip}!" }

JavaScript(Node.js)

파워!

var input = [];
require('readline')
.createInterface(process.stdin, {})
.on('line', function(line) {
  input.push(line.trim());
}).on('close', function() {
  for (var i = 1; i <= +input[0]; i++)
    console.log('Hello, ' + input[i] + '!');
});

Go

package main
import "fmt"
func main() {
        var cases int
        var name string
        fmt.Scanf("%d", &cases)
        for cases > 0 {
                fmt.Scanf("%s", &name)
                fmt.Printf("Hello, %s!\n", name)
                cases--
        }
}

서브밋하기

문제 위 오른쪽의 제출 버튼을 누르고 소스 코드를 붙여넣으면 서브미션 결과 페이지로 이동하게 된다.

붉은색으로 정답이라는 말이 떴으면 성공!