LoginSignup
0
0

More than 5 years have passed since last update.

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

Last updated at Posted at 2018-05-04

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

問題 : http://nabetani.sakura.ne.jp/hena/orde18twintri/
実装リンク集 : https://qiita.com/Nabetani/items/891d07f4d645ec00ce9a

三角形をすべて含む矩形の面積を S として、
O(S)ぐらいの遅い実装。

実装
package e18

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

func iabs(x int) int {
    if x < 0 {
        return -x
    }
    return x
}

type triangle struct {
    x, y int
    dir  byte
    h    int
}

func (t triangle) contains(x, y int) bool {
    dx := x - t.x
    dy := y - t.y
    switch t.dir {
    case 'L':
        return 0 <= dx && iabs(dy) <= dx && dx < t.h
    case 'R':
        return dx <= 0 && iabs(dy) <= -dx && -dx < t.h
    case 'T':
        return 0 <= dy && iabs(dx) <= dy && dy < t.h
    case 'B':
        return dy <= 0 && iabs(dx) <= -dy && -dy < t.h
    default:
        panic(struct{}{})
    }
}

func (t triangle) minX() int {
    switch t.dir {
    case 'R':
        return t.x - t.h + 1
    case 'L':
        return t.x
    case 'T', 'B':
        return t.x - t.h + 1
    default:
        panic(struct{}{})
    }
}

func (t triangle) maxX() int {
    switch t.dir {
    case 'R':
        return t.x
    case 'L':
        return t.x + t.h - 1
    case 'T', 'B':
        return t.x + t.h - 1
    default:
        panic(struct{}{})
    }
}

func (t triangle) minY() int {
    switch t.dir {
    case 'R', 'L':
        return t.y - t.h + 1
    case 'T':
        return t.y
    case 'B':
        return t.y - t.h + 1
    default:
        panic(struct{}{})
    }
}

func (t triangle) maxY() int {
    switch t.dir {
    case 'R', 'L':
        return t.x + t.h - 1
    case 'T':
        return t.y + t.h - 1
    case 'B':
        return t.y
    default:
        panic(struct{}{})
    }
}

func intMin(a, b int) int {
    if a < b {
        return a
    }
    return b
}

func intMax(a, b int) int {
    if a < b {
        return b
    }
    return a
}

func parseTriangle(s string) triangle {
    var t triangle
    fmt.Sscanf(s, "%d,%d%c%d", &t.x, &t.y, &t.dir, &t.h)
    return t
}

func impl(a, b triangle) int {
    minx := intMin(a.minX(), b.minX())
    miny := intMin(a.minY(), b.minY())
    maxx := intMax(a.maxX(), b.maxX())
    maxy := intMax(a.maxY(), b.maxY())
    count := 0
    for y := miny; y <= maxy; y++ {
        for x := minx; x <= maxx; x++ {
            if a.contains(x, y) && b.contains(x, y) {
                count++
            }
        }
    }
    return count
}

func solve(src string) string {
    split := strings.Split(src, "/")
    var triangles [2]triangle
    for i := 0; i < 2; i++ {
        triangles[i] = parseTriangle(split[i])
    }
    count := impl(triangles[0], triangles[1])
    return strconv.Itoa(count)
}
テスト
package e18

import (
    "testing"
)

func Test(t *testing.T) {
    var tests = []struct {
        name  string
        input string
        want  string
    }{
        {"0", "7,0R6/3,1B5", "15"},
        {"1", "1,6L4/4,9R9", "4"},
        {"2", "0,2R4/1,3B4", "3"},
        {"3", "1,2L4/1,2L5", "16"},
        // 中略
        {"46", "5621,8460T7612/2715,5697L8851", "861192"},
    }
    for _, test := range tests {
        got := solve(test.input)
        if got != test.want {
            t.Errorf("%v: solve(%q)=%q, want %q\n", test.name, test.input, got, test.want)
        }
    }
}

130行以上書いてしまった。もう少しサボっても良かったか。
遅いアルゴリズムだけど、手元で実行すると 4秒弱。
たぶん数倍無駄があるruby版( https://qiita.com/Nabetani/items/c6dd56eeacebada2bad8 )が 1分弱なので、速いことは速い。

家で書いていると、のんびりしてしまうのが良くないね。
もっと追い込まれて書いたほうがよい気がする。

今回の収穫は Sscanf
意地悪されない限り、Sscanf を使えば多少複雑でもパースはOKになると思われる。

panic の引数に何を入れていいのかからなかったので、struct{}{} を入れてみたんだけど、普通どうするんだろ。
エラーメッセージの文字列入れるのかなぁ。

Go の手習いとしては、構造体とメンバ関数(?)を、問題解決のためとしては初めて書いた。

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