[MEETING] [golang] 시간초과 오류

  • User Avatar
    bupjae

    [[problem:MEETING]] 문제를 풀기 위해 다음과 같은 go 코드를 작성하였습니다:


    ~~~ go
    package main

    import "fmt"
    import "sort"

    func main() {
    var t int
    fmt.Scan(&t)
    for i := 0; i < t; i++ {
    var n int
    fmt.Scan(&n)
    m := make([]int, n)
    w := make([]int, n)
    for j := 0; j < n; j++ {
    fmt.Scan(&m[j])
    }
    for j := 0; j < n; j++ {
    fmt.Scan(&w[j])
    }
    sort.Ints(m)
    sort.Ints(w)
    r := 0
    for j := 0; j < n; j++ {
    rr := m[j] - w[j]
    if rr < 0 {
    rr *= -1
    }
    r += rr
    }
    fmt.Println(r)
    }
    }
    ~~~

    제출을 했더니 "시간초과" 오류를 받았습니다.

    라이브러리에서 제공된 sort 알고리즘에 문제가 있나 라고 생각해서 sort를 직접 구현해서 다시 제출했습니다:


    ~~~ go
    package main

    import "fmt"

    func sort(a []int) []int {
    if len(a) < 2 {
    return a
    }
    r := make([]int, 0, len(a))
    b := sort(a[:len(a)/2])
    c := sort(a[len(a)/2:])
    for len(b) > 0 && len(c) > 0 {
    if b[0] < c[0] {
    r = append(r, b[0])
    b = b[1:]
    } else {
    r = append(r, c[0])
    c = c[1:]
    }
    }
    r = append(r, b...)
    return append(r, c...)
    }

    func main() {
    var t int
    fmt.Scan(&t)
    for i := 0; i < t; i++ {
    var n int
    fmt.Scan(&n)
    m := make([]int, n)
    w := make([]int, n)
    for j := 0; j < n; j++ {
    fmt.Scan(&m[j])
    }
    for j := 0; j < n; j++ {
    fmt.Scan(&w[j])
    }
    sort(m)
    sort(w)
    r := 0
    for j := 0; j < n; j++ {
    rr := m[j] - w[j]
    if rr < 0 {
    rr *= -1
    }
    r += rr
    }
    fmt.Println(r)
    }
    }
    ~~~

    하지만 이 프로그램도 시간초과에 걸렸습니다.

    이 결과를 도저히 받아들일 수 없어서, 이 프로그램을 그대로 C++로 옮겨서 구현했습니다:


    ~~~ c++
    #include
    #include
    using namespace std;

    int intcomp(const void *v1, const void *v2) {
    return ((const int)v1) - ((const int)v2);
    }

    int main() {
    int t;
    scanf("%d", &t);
    for(int i=0; i int n;
    scanf("%d", &n);
    int *m = new int[n];
    int *w = new int[n];
    for(int j=0; j scanf("%d", &m[j]);
    }
    for(int j=0; j scanf("%d", &w[j]);
    }
    qsort(m, n, sizeof(int), intcomp);
    qsort(w, n, sizeof(int), intcomp);
    int r = 0;
    for(int j=0; j int rr=m[j]-w[j];
    if(rr<0) rr*=-1;
    r+=rr;
    }
    printf("%d\n", r);
    delete[] m;
    delete[] w;
    }
    }
    ~~~

    75ms만에 정답을 받았습니다.

    go 언어를 배우면서 이 사이트에 올려진 문제를 풀려고 하고 있습니다만, 이 정도 문제에서조차 시간초과 오류를 받아버리면 아무래도 go 언어로 문제를 푸는 것 자체가 어렵지 않을까 생각되어 문제제기를 해 봅니다.

    *** 수정: 입력 방식에 따른 속도 차이를 고려, 좀 더 빠른 방식인 bufio.Scanner 로 다시 구현해봤습니다:


    ~~~ go
    package main

    import "bufio"
    import "fmt"
    import "os"
    import "sort"
    import "strconv"

    type MyScanner struct {
    in *bufio.Scanner
    }

    var in = MyScanner{bufio.NewScanner(os.Stdin)}

    func ScanInts(data []byte, atEOF bool) (advance int, token []byte, err error) {
    advance, token, err = bufio.ScanWords(data, atEOF)
    if err == nil && token != nil {
    _, err = strconv.Atoi(string(token))
    }
    return
    }

    func (m *MyScanner) innerNext(f bufio.SplitFunc) bool {
    m.in.Split(f)
    return m.in.Scan()
    }

    func (m *MyScanner) NextInt() (int, error) {
    if !m.innerNext(ScanInts) {
    return 0, m.in.Err()
    }
    r, _ := strconv.Atoi(m.in.Text())
    return r, nil
    }

    func main() {
    t, _ := in.NextInt()
    for i := 1; i <= t; i++ {
    main2(i)
    }
    }

    func main2(caseCount int) {
    n, _ := in.NextInt()
    m := make([]int, n)
    w := make([]int, n)
    for j := 0; j < n; j++ {
    m[j], _ = in.NextInt()
    }
    for j := 0; j < n; j++ {
    w[j], _ = in.NextInt()
    }
    sort.Ints(m)
    sort.Ints(w)
    r := 0
    for j := 0; j < n; j++ {
    rr := m[j] - w[j]
    if rr < 0 {
    rr *= -1
    }
    r += rr
    }
    fmt.Println(r)
    }
    ~~~

    208ms 만에 정답을 받았습니다.
    물론 C++에 비해 다소 느리긴 하지만, 이 정도 차이는 충분히 납득 가능합니다.


    12년 전
7개의 댓글이 있습니다.
  • User Avatar
    Being

    게시판을 검색해 보시면 Go 뿐만이 아니라 다른 언어에서도 마찬가지의 문제가 발생하고 있습니다. 그러나 언어별로 다른 시간 제한을 적용할 계획은 현재로는 없습니다. 단순히 특정 언어엔 몇 배의 시간을 더 주는 식으로 해결할 수 있는 문제가 아니라고 보고 있습니다. 반대로 공평하게 모든 언어에 같은 시간을 적용하게 되면 C++로 시간복잡도가 느리게 작성된 알고리즘이 다른 언어로 최대한 빠르게 작성한 답안보다 빠른 경우가 빈번해서 문제가 됩니다. 다른 좋은 의견 있으시면 참고하겠습니다.


    12년 전 link
  • User Avatar
    bupjae

    startup 또는 input/output 등에서 발생할 수 있는 시간 차이의 여지를 완전히 사전 차단하는 TopCoder 방식의 채점 시스템을 도입하면 문제가 해결될 거라는 (헛된) 기대를 합니다만, 이 곳에 적용하기에는 사실상 불가능할 것 같기에 그냥 잡설로만 남깁니다.

    go 로 짠 코드를 c++ 로 옮기는 거야 쉽게 할 수 있습니다만, 가슴 아픈 건 제 프로필에 억울하게 남는 실패 횟수/역사...... :(


    12년 전 link
  • User Avatar
    Being

    입출력이 많은 경우 가장 큰 이슈죠.. 아무래도 다른 언어로 푸는 분들이 많지는 않다보니 문제별로 검토하기엔 샘플을 모으기도 어려운 부분이 있습니다.


    12년 전 link
  • User Avatar
    bupjae

    [[problem:COINS]]도 go로 풀었을 때 시간초과가 났길래 더 좋은 알고리즘 찾다가 안되서 포기하고 있었는데
    이번 사태를 계기로 기존에 작성한 go 프로그램을 그대로 c++로 옮겨서 넣었더니 아니나 다를까 정답 뜨네요.

    오답 기록이 아프긴 하지만, 남들보다 2배로 배워간다고 생각하겠습니다 :)


    12년 전 link
  • User Avatar
    일루

    입출력과 실제 실행 중 어느쪽이 bottleneck인지 알면 좋을 것 같습니다. 확인해보고 알려드릴께요.


    12년 전 link
  • User Avatar
    heekyu

    시간재는 코드가 어떤 식으로 구현되어 있는지 모르겠는데요,
    만약 프로그램 실행부터 끝날 때까지 시간을 재는 방식이라면
    입출력, 실제 실행 이외에도 요소들에 의해 수행시간에서 패널티가 존재할 것 같습니다.
    저는 주로 java로 짜는데요
    java는 실행할 때 JVM system library들도 뜨고 bytecode 컴파일도 런타임에 이루어집니다.
    입출력도 미미하고 실제로 하는 일도 별로 없는 코드를 돌려도 기본적으로 100ms~200ms는 먹고 들어갑니다.

    https://algospot.com/judge/submission/detail/212001
    이건 루프 8번 돌고 끝나는데 시간초과(1000ms)가 납니다.

    다른 언어들은 상황을 자세히 모르지만 비슷한 문제들을 가지고 있지 않을까 예상해 봅니다.

    물론 이건 실제 채점 모듈이 어떻게 되어 있는지 모르는 상태에서 한 추측이므로 사실과 다를 수 있습니다만,
    확인해 본다고 하셨으니 이런 부분도 같이 고려해 보시면 좋을 것 같습니다.


    12년 전 link
  • User Avatar
    wookayin

    개인적으로는, 언어별로 제한시간 버퍼를 좀 두는게 좋을거 같다는 의견에는 동의하는 편입니다.


    12년 전 link
  • 정회원 권한이 있어야 커멘트를 다실 수 있습니다. 정회원이 되시려면 온라인 저지에서 5문제 이상을 푸시고, 가입 후 7일 이상이 지나셔야 합니다. 현재 문제를 푸셨습니다.