LoginSignup
0
0

More than 5 years have passed since last update.

オフラインリアルタイムどう書く E22 の実装例(Go で 腕力)

Last updated at Posted at 2018-04-19

オフラインリアルタイムどう書く E22 の実装例(Go で 腕力)
問題 : http://nabetani.sakura.ne.jp/hena/orde22numord/
解答リンク集 : https://qiita.com/Nabetani/items/99e38a39165e1905b415

で。

ナイーブな実装を go で書いてみた。

実装
package e22

import (
    "fmt"
    "sort"
    "strconv"
    "strings"
)

func impl(m int, n int, b int, x int) int {
    values := make([]string, 0, n-m+1)
    for i := m; i <= n; i++ {
        values = append(values, strconv.FormatInt(int64(i), b))
    }
    sort.Strings(values)
    val, _ := strconv.ParseInt(values[x-1], b, 32)
    return int(val)
}

func solve(src string) string {
    split := strings.Split(src, ",")
    fmt.Println(split)
    m, _ := strconv.Atoi(split[0])
    n, _ := strconv.Atoi(split[1])
    b, _ := strconv.Atoi(split[2])
    x, _ := strconv.Atoi(split[3])
    return strconv.Itoa(impl(m, n, b, x))
}
テスト
package e22

import (
    "testing"
)

func TestE22(t *testing.T) {
    var tests = []struct {
        name  string
        input string
        want  string
    }{
        {"0", "2,15,3,8", "14"},
        {"1", "6,8,8,1", "8"},
        {"2", "6,6,5,1", "6"},
        // 中略
        {"36", "66097362,104618756,16,32740764", "98838125"},
    }
    ch := make(chan struct{}, len(tests))
    for _, test := range tests {
        go func(name, input, want string) {
            got := solve(input)
            if got != want {
                t.Errorf("%v: solve(%q)=%q, want %q\n", name, input, got, want)
            }
            ch <- struct{}{}
        }(test.name, test.input, test.want)
    }
    for range tests {
        <-ch
    }
}

実装の方はシングルスレッドで、テストの方で goルーチンを使ってみた。
結果、 118秒。まあそんなもんか。
テストで goルーチンを使わないと 244秒。倍しか違わない。
C++ で OpenMP を使わない実装( see https://qiita.com/Nabetani/items/cbf55992627452a9be67 )が2分半から3分ちょっとなので、go の方がちょと遅い感じ。

とはいえ。
C++ の方は vector<array<char,32>> なので、速くて当たり前か。

しかし。 string[32]byte に変えた実装

実装2
package e22

import (
    "sort"
    "strconv"
    "strings"
)

func toBytes(n, b int) [32]byte {
    var s [32]byte
    var m [32]byte
    i := 0
    for 0 < n {
        m[i] = byte((n % b) + 1)
        n /= b
        i++
    }
    for j := 0; j < i; j++ {
        s[j] = m[i-j-1]
    }
    s[i] = 0
    return s
}

func toNum(c [32]byte, b int) int {
    r := 0
    for pos := 0; 0 != c[pos]; pos++ {
        r *= b
        r += int(c[pos]) - 1
    }
    return r
}

type NumsSlice [][32]byte

func (s NumsSlice) Len() int {
    return len(s)
}

func (s NumsSlice) Less(i, j int) bool {
    sa := s[i]
    sb := s[j]
    for pos := 0; ; pos++ {
        a := sa[pos]
        b := sb[pos]
        if a < b {
            return true
        }
        if b < a {
            return false
        }
    }
}

func (s NumsSlice) Swap(i, j int) {
    tmp := s[i]
    s[i] = s[j]
    s[j] = tmp
}

func impl(m int, n int, b int, x int) int {
    values := NumsSlice(make([][32]byte, 0, n-m+1))
    for i := m; i <= n; i++ {
        values = append(values, toBytes(i, b))
    }
    sort.Sort(values)
    val := toNum(values[x-1], b)
    return int(val)
}

func solve2(src string) string {
    split := strings.Split(src, ",")
    m, _ := strconv.Atoi(split[0])
    n, _ := strconv.Atoi(split[1])
    b, _ := strconv.Atoi(split[2])
    x, _ := strconv.Atoi(split[3])
    return strconv.Itoa(impl(m, n, b, x))
}

の方が遅く、シングルスレッドで 340秒なのであった。ぐぬぬ。
やっぱり C++ の方が速い模様。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0