- 投稿日:2020-09-28T21:57:08+09:00
Excelize 2.3.1がリリース–スプレッドシート(Excel)ファイル用のGoライブラリ、パスワードで保護されたスプレッドシートの読み取りをサポート
Excelize は、ECMA-376 Office OpenXML 標準に基づいて Office Excel ドキュメントを操作するための Go 言語で書かれたクラスライブラリです。 XLSX ファイルの読み書きに使用できます。Excelize は、他のオープンソースライブラリと比較して、イメージ(テーブル)付きのドキュメントの作成、Excel へのイメージの挿入、および保存後のチャートスタイルの保存をサポートしており、さまざまなレポートシステムに適用できます。
場合によっては、既存の Excel ドキュメントコンテンツの読み込み、新しい Excel ドキュメントの作成、既存のドキュメント(テンプレート)に基づく新しい Excel ドキュメントの生成、Excel ドキュメントへのイメージの挿入、チャートなどの Excel ドキュメントをプログラムで操作する必要があります。 テーブルなどの要素。プラットフォーム間でこれらの操作を実装する必要がある場合があります。Excelize はこれらのニーズを容易に満たすことができます。
オープンソース
GitHub: github.com/xuri/excelize
Doc: xuri.me/excelize/ja
リリースノート
このリリースで最も注目すべき変更は次のとおりです。
注目すべき機能
- ECMA-376 ドキュメント標準暗号化によるパスワード保護付きのオープンスプレッドシートをサポートし、問題 #199 を関連付けます
- ワークシートのチェックと制限を追加します
- ピボットテーブル機能の拡張:ピボットテーブルのヘッダー、スタイル、およびテーブルオプションの設定をサポート
- セキュリティの脆弱性とパッチ
互換性を向上させる
- Go 1.15 と互換性があり、Windows でユニットテストが失敗し、潜在的な競合状態が発生します。問題#689を関連付けてください。
- Apache Open Office および Kingsoft WPS™ とのデフォルトの行の高さの互換性
- ふりがなのヒントとシートのタブの色の互換性を改善
バグの修正
- 範囲外の
RemoveRow
スライスの境界を修正すると、場合によってはパニックが発生します。#686を解決してください。- ストリームライターが生成した破損したファイルの問題を修正する
- 画像の追加が機能しないようにスケールを修正し、#691を解決します
雑多
- エラー処理の改善と無効なスプレッドシートファイルを開いたときのクラッシュの修正
- 多言語対応のドキュメント Web サイト:英語、フランス語、ロシア語、中国語、日本語、韓国語。更新されました。
- Slack チャンネルに参加して、コミュニティの他のメンバーに会いにようこそ
- 投稿日:2020-09-28T21:57:08+09:00
Excelize 2.3.1 がリリース–スプレッドシート(Excel)ファイル用の Go ライブラリ、パスワードで保護されたスプレッドシートの読み取りをサポート
Excelize は、ECMA-376 Office OpenXML 標準に基づいて Office Excel ドキュメントを操作するための Go 言語で書かれたクラスライブラリです。 XLSX ファイルの読み書きに使用できます。Excelize は、他のオープンソースライブラリと比較して、イメージ(テーブル)付きのドキュメントの作成、Excel へのイメージの挿入、および保存後のチャートスタイルの保存をサポートしており、さまざまなレポートシステムに適用できます。
場合によっては、既存の Excel ドキュメントコンテンツの読み込み、新しい Excel ドキュメントの作成、既存のドキュメント(テンプレート)に基づく新しい Excel ドキュメントの生成、Excel ドキュメントへのイメージの挿入、チャートなどの Excel ドキュメントをプログラムで操作する必要があります。 テーブルなどの要素。プラットフォーム間でこれらの操作を実装する必要がある場合があります。Excelize はこれらのニーズを容易に満たすことができます。
オープンソース
GitHub: github.com/xuri/excelize
Doc: xuri.me/excelize/ja
リリースノート
このリリースで最も注目すべき変更は次のとおりです。
注目すべき機能
- ECMA-376 ドキュメント標準暗号化によるパスワード保護付きのオープンスプレッドシートをサポートし、問題 #199 を関連付けます
- ワークシートのチェックと制限を追加します
- ピボットテーブル機能の拡張:ピボットテーブルのヘッダー、スタイル、およびテーブルオプションの設定をサポート
- セキュリティの脆弱性とパッチ
互換性を向上させる
- Go 1.15 と互換性があり、Windows でユニットテストが失敗し、潜在的な競合状態が発生します。問題#689を関連付けてください。
- Apache Open Office および Kingsoft WPS™ とのデフォルトの行の高さの互換性
- ふりがなのヒントとシートのタブの色の互換性を改善
バグの修正
- 範囲外の
RemoveRow
スライスの境界を修正すると、場合によってはパニックが発生します。#686を解決してください。- ストリームライターが生成した破損したファイルの問題を修正する
- 画像の追加が機能しないようにスケールを修正し、#691を解決します
雑多
- エラー処理の改善と無効なスプレッドシートファイルを開いたときのクラッシュの修正
- 多言語対応のドキュメント Web サイト:英語、フランス語、ロシア語、中国語、日本語、韓国語。更新されました。
- Slack チャンネルに参加して、コミュニティの他のメンバーに会いにようこそ
- 投稿日:2020-09-28T11:33:04+09:00
Googleマップで宝探し!たんけんぼくのかそうまちゲーム
前々から温めてたのに実装方法が思いつかなかったんだけど、ようやくプロト出来た!
まえせつ
自分の住んでいる町を迷路とかゲームのマップとして簡単に使えたら、遊び方が広がらないかなって思っててOpenStreetMap→Blender変換とかやってたけどうまくいかなくって。
で、とある日、ぼーっとGoogleマップ見てたら
https://www.google.co.jp/maps/@35.6608375,139.7008749,3a,75y,43.91h,92.5t/data=!3m6!1e1!3m4!1sDrFpHa0VreQbapnpTC-QgA!2e0!7i16384!8i8192あれ・・?このURLの"@"の後って緯度経度・・・?
!!!!!!!!
こっからの実装へのブレークスルーは実に早かった。
つくってみたわ
宝探しを通じて現実の町探検を仮想で楽しむゲームです。
- Googleマップの緯度・経度を使って各プレイヤーのスタート地点とゴールを決めます
- ゴールまでにヒントのテキストや、画像を仕掛けたりできます
- プレイヤー同士でメッセージをやりとりしたり、書置きを読んだりできます
・Windows、Linux、Rasbian対応のGolang製Websocketサーバー
サーバーとするPCで動かしてください。
・Chrome拡張 (Chromiumも対応)
ゲームする端末上のChrome(と互換ブラウザ)で動かしてください。サーバーと同居できます。
じゅんび:
Googleマップで遊びたい町を開いてください。
こんなかんじでURL出ますんで下線の緯度経度をピックアップしてコンフィグを作ります。
コンフィグの例は以下です。[PLAYER] https://www.google.co.jp/maps/@35.6608375,139.7008749,3a,75y,43.91h,92.5t/data=!3m6!1e1!3m4!1sDrFpHa0VreQbapnpTC-QgA!2e0!7i16384!8i8192 https://www.google.co.jp/maps/@35.6613982,139.7001959,3a,75y,131.45h,104.53t/data=!3m6!1e1!3m4!1szZPFU_fUtAcf-e3DGysGlw!2e0!7i16384!8i8192 [GOAL] 35.6618983,139.7008538 [RESULT] ゴールに着きました! [ACTION] 35.6602069,139.7007403 マックに着きました~ 35.6632348,139.701151 https://www.google.co.jp/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png
- [PLAYER]はスタート地点です。URLをベタ貼りしてください。遊ぶ人数分貼ってください。
- [GOAL]は目的地(ゴール)の緯度・経度を書いてください
- [RESULT]はゴール時のメッセージです。httpから始まるURL指定で画像も指定できます
- [ACTION]は緯度経度とメッセージをタブで区切ったもので来た時にメッセージや画像を表示します
緯度経度を調べながらヒント作ったり、画像貼ったりでゲームの"面"を作ってください
きどうほうほう:
始めにGo言語のWebsocketサーバーを起動します。同フォルダにコンフィグ置いて実行すれば動きます。
次にChrome拡張インストールします。ブラウザとサーバーが別PCの場合は拡張のアイコンを開いて「接続サーバー」欄にサーバーのIPアドレスとポート番号を指定してください。保存して拡張を再起動します。
IPアドレスとポート番号はサーバー上に10秒に一回表示されますjoin client!と出たら接続成功です。スタート地点のマップが自動的に開きます。
うごかしかた:
ルールとしては宝探しなのでGoogleマップで一番先に目的地に着けば良いです。その他は要素はゲーム装飾です。
コンフィグで指定した任意の場所でメッセージを出せます
任意の場所で画像も出せます
SNSぽく、参加者全員にメッセージを表示できます。
他プレイヤーにお知らせが出ました
特定の場所に書置きができます。メッセージ通知を後から追加できる機能です
あとがき
バーチャルリアリティはあくまで仮想の世界であってリアリティが今一つだと思ってる。
人がアバターになって出てきても、街という人の生活感が感じられる部分が薄いからと思ってる。
このゲームは現実の町で、仮想的に探検するという真逆の発想で産まれました。
たぶん他に無いアイディアなのでSNS化など、もっともっと育てたいです。
- 投稿日:2020-09-28T01:54:59+09:00
Goの環境変数を扱う(viper)
はじめに
golangで環境設定ファイルを簡単にするライブラリとしてviperというものがあります。
今回はそのviperの使い方を簡単に紹介しますviper
シンプルにviperを使ってみる
今回は構造体にマッピングしてそれを引き回して使うように実装を行いますソースツリー. ├── config │ ├── config.yaml │ └── definition.go └── main.goconfig.yaml# 環境変数設定用のyamlファイル user: name: "kosuke"本来はデータベースのユーザー名等を入れることが多いですが、今回は簡単に上記のような環境変数を設定します。
definition.gopackage config import ( "fmt" "github.com/spf13/viper" ) // マッピング用の構造体 type Config struct { User User `yaml:user` } type User struct { Name string `yaml:"name"` } func Load() (*Config, error) { viper.SetConfigName("config") // 設定ファイル名を指定 viper.SetConfigType("yaml") // 設定ファイルの形式を指定 viper.AddConfigPath("config/") // ファイルのpathを指定 err := viper.ReadInConfig() // 設定ファイルを探索して読み取る if err != nil { return nil, fmt.Errorf("設定ファイル読み込みエラー: %s \n", err) } var cfg Config err = viper.Unmarshal(&cfg) if err != nil { return nil, fmt.Errorf("unmarshal error: %s \n", err) } return &cfg, nil }
Load()
と言う関数の中で、環境変数のファイルを探しConfig
という構造体に環境変数をマッピングしていきますmain.gopackage main import ( "fmt" "viper-test/config" ) func main() { cfg, err := config.Load() if err != nil { panic(err) } fmt.Println(cfg.User.Name) }今回は構造体にデータが入っていることを確かめるために
Config
の中身を表示しているだけですが、
本来であればこの構造体を引数に撮ってDBコネクション等を行っていきます。$ go run main.go kosuke
また、本番環境で運用等を行うときは外部から環境変数を受けとりたいということがあると思います。
その際は、、、definition.gopackage config import ( "fmt" "github.com/spf13/viper" ) // マッピング用の構造体 type Config struct { User User `yaml:user` } type User struct { Name string `yaml:"name"` } func Load() (*Config, error) { viper.SetConfigName("config") viper.SetConfigType("yaml") viper.AddConfigPath("config/") // ===========↓追記============= // 環境変数がすでに指定されてる場合はそちらを優先させる viper.AutomaticEnv() // データ構造をキャメルケースに切り替える用の設定 viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) // ===========↑ここまで============= err := viper.ReadInConfig() if err != nil { return nil, fmt.Errorf("設定ファイル読み込みエラー: %s \n", err) } var cfg Config err = viper.Unmarshal(&cfg) if err != nil { return nil, fmt.Errorf("unmarshal error: %s \n", err) } return &cfg, nil }上記のような構文を使うことで環境変数が指定された時にはconfigファイルの値ではなく、
環境変数の値を参照することができます# 環境変数を与えて `go run` $ USER_NAME=tarou go run main.go tarou終わりに
今回はとてもシンプルな使い方でしたが、環境変数を構造体にマッピングして引き回していくのは余計な処理を書かなくて済むのてとても楽かなと思います。
もちろんですが、、、秘匿情報の扱い(AWSのアクセスキーなど)には気をつけて使用していきたいところです。参考資料
- viper(https://github.com/spf13/viper )
- 投稿日:2020-09-28T00:30:47+09:00
AtCoder Chokudai Contest 005 参戦記
AtCoder Chokudai Contest 005 参戦記
参加しなくていいかなあと思いつつ、結局参加してしまうやつ.
結果は49,656,737点で、AC 528人中240位でした. 最終コードは以下で Go 言語で提出しました.
package main import ( "bufio" "fmt" "math" "os" "strconv" ) func min(x, y int) int { if x < y { return x } return y } func fill(d [][]byte, i, j int, x, y byte) { q := [][2]int{{i, j}} for len(q) != 0 { m, n := q[0][0], q[0][1] q = q[1:] d[m][n] = x if m > 0 { if d[m-1][n] == y { q = append(q, [2]int{m - 1, n}) } } if m < N-1 { if d[m+1][n] == y { q = append(q, [2]int{m + 1, n}) } } if n > 0 { if d[m][n-1] == y { q = append(q, [2]int{m, n - 1}) } } if n < N-1 { if d[m][n+1] == y { q = append(q, [2]int{m, n + 1}) } } } } // var ( N int ) func main() { defer flush() _ = readInt() N = readInt() K := readInt() S := make([]string, N) for i := 0; i < N; i++ { S[i] = readString() } d := make([][]byte, N) for i := 0; i < N; i++ { d[i] = make([]byte, N) } result := make([][]string, 0, K) for n := 1; n <= K; n++ { x := byte(n + '0') t := make([]string, 0, 10000) for i := 0; i < N; i++ { for j := 0; j < N; j++ { d[i][j] = S[i][j] } } for i := 1; i < N-1; i++ { for j := 1; j < N-1; j++ { if d[i][j] == x { continue } a := 0 b := 0 if d[i-1][j] != d[i][j] { a++ if d[i-1][j] == d[i+1][j] { a++ } if d[i-1][j] == d[i][j+1] { a++ } } else if d[i][j-1] != d[i][j] { b++ if d[i][j-1] == d[i+1][j] { b++ } if d[i][j-1] == d[i][j+1] { b++ } } if a == 0 && b == 0 { continue } var c byte if a >= b { c = d[i-1][j] } else { c = d[i][j-1] } t = append(t, fmt.Sprintf("%d %d %c", i+1, j+1, c)) fill(d, i, j, c, d[i][j]) } } for i := 0; i < N; i++ { for j := 0; j < N; j++ { if d[i][j] == x { continue } t = append(t, fmt.Sprintf("%d %d %c", i+1, j+1, x)) fill(d, i, j, x, d[i][j]) } } result = append(result, t) } best := math.MaxInt64 for i := 0; i < K; i++ { best = min(best, len(result[i])) } bestIndex := -1 for i := 0; i < K; i++ { if len(result[i]) == best { bestIndex = i break } } println(best) for i := 0; i < best; i++ { println(result[bestIndex][i]) } } const ( ioBufferSize = 1 * 1024 * 1024 // 1 MB ) var stdinScanner = func() *bufio.Scanner { result := bufio.NewScanner(os.Stdin) result.Buffer(make([]byte, ioBufferSize), ioBufferSize) result.Split(bufio.ScanWords) return result }() func readString() string { stdinScanner.Scan() return stdinScanner.Text() } func readInt() int { result, err := strconv.Atoi(readString()) if err != nil { panic(err) } return result } var stdoutWriter = bufio.NewWriter(os.Stdout) func flush() { stdoutWriter.Flush() } func println(args ...interface{}) (int, error) { return fmt.Fprintln(stdoutWriter, args...) }感想、反省点など
- Introduction to Heuristics Contest で学んだ局所探索法が全く使えなかったのが残念.
- Introduction to Heuristics Contest は貪欲法の部分が悪くて余り点が伸びなかったのだが、今回はそこは結構がんばれた感があってよかった.
タイムライン
以下は大まかなタイムラインです.
- [21:00] YouTube で動画見てた(ぉぃ).
- [21:07] アァァ! となって急いで https://atcoder.jp/ にアクセスした.
- [21:07] 一応 checker.zip を拾って斜め読みした.
- [21:12] 問題文を読んで、何もしなくても一応 AC はするんだなと思い、以下を提出して5807500点をゲット.
id, N, K = map(int, input().split()) S = [input() for _ in range(N)] print(0)
- [21:25] 取り敢えず最初に一番多い色に塗りつぶすかと思い、以下を提出して49558075点をゲット.
from collections import Counter id, N, K = map(int, input().split()) S = [input() for _ in range(N)] c = Counter() for i in range(N): c.update(S[i]) x = c.most_common(1)[0][0] result = [] for i in range(N): for j in range(N): if S[i][j] != x: result.append('%d %d %s' % (i + 1, j + 1, x)) print(len(result)) print(*result, sep='\n')
- [21:37] 左と上が同じ色の場合は既に塗る必要がないなと思い、以下を提出して49649188点をゲット.
from collections import Counter id, N, K = map(int, input().split()) S = [input() for _ in range(N)] c = Counter() for i in range(N): c.update(S[i]) x = c.most_common(1)[0][0] result = [] for i in range(N): for j in range(N): if S[i][j] != x and (i == 0 or S[i][j] != S[i - 1][j]) and (j == 0 or S[i][j] != S[i][j - 1]): result.append('%d %d %s' % (i + 1, j + 1, x)) print(len(result)) print(*result, sep='\n')
- [21:42] 別に全色試してもいいんじゃねって気づき、以下を提出して49649427点をゲット. 99位.
id, N, K = map(int, input().split()) S = [input() for _ in range(N)] result = [] for n in range(1, K + 1): x = str(n) t = [] for i in range(N): for j in range(N): if S[i][j] != x and (i == 0 or S[i][j] != S[i - 1][j]) and (j == 0 or S[i][j] != S[i][j - 1]): t.append('%d %d %s' % (i + 1, j + 1, x)) result.append(t) best = min(len(result[i]) for i in range(K)) for i in range(K): if len(result[i]) == best: best_index = i break print(len(result[best_index])) print(*result[best_index], sep='\n')
- [22:13] 塗るシミュレーションをしたいなと思い、Go 言語に移植し完了する.
- [22:22] 塗るシミュレーションを入れたコードを提出し、49654250点をゲット. 184位.
package main import ( "bufio" "fmt" "math" "os" "strconv" ) func min(x, y int) int { if x < y { return x } return y } func main() { defer flush() _ = readInt() N := readInt() K := readInt() S := make([]string, N) for i := 0; i < N; i++ { S[i] = readString() } d := make([][]byte, N) for i := 0; i < N; i++ { d[i] = make([]byte, N) } result := make([][]string, 0, K) for n := 1; n <= K; n++ { x := byte(n + '0') t := make([]string, 0, 10000) for i := 0; i < N; i++ { for j := 0; j < N; j++ { d[i][j] = S[i][j] } } for i := 0; i < N; i++ { for j := 0; j < N; j++ { if d[i][j] != x { s := fmt.Sprintf("%d %d %c", i+1, j+1, x) t = append(t, s) y := d[i][j] q := [][2]int{[2]int{i, j}} for len(q) != 0 { m, n := q[0][0], q[0][1] q = q[1:] d[m][n] = x if m > 0 { if d[m-1][n] == y { q = append(q, [2]int{m - 1, n}) } } if m < N-1 { if d[m+1][n] == y { q = append(q, [2]int{m + 1, n}) } } if n > 0 { if d[m][n-1] == y { q = append(q, [2]int{m, n - 1}) } } if n < N-1 { if d[m][n+1] == y { q = append(q, [2]int{m, n + 1}) } } } } } } result = append(result, t) } best := math.MaxInt64 for i := 0; i < K; i++ { best = min(best, len(result[i])) } bestIndex := -1 for i := 0; i < K; i++ { if len(result[i]) == best { bestIndex = i break } } println(best) for i := 0; i < best; i++ { println(result[bestIndex][i]) } } const ( ioBufferSize = 1 * 1024 * 1024 // 1 MB ) var stdinScanner = func() *bufio.Scanner { result := bufio.NewScanner(os.Stdin) result.Buffer(make([]byte, ioBufferSize), ioBufferSize) result.Split(bufio.ScanWords) return result }() func readString() string { stdinScanner.Scan() return stdinScanner.Text() } func readInt() int { result, err := strconv.Atoi(readString()) if err != nil { panic(err) } return result } var stdoutWriter = bufio.NewWriter(os.Stdout) func flush() { stdoutWriter.Flush() } func println(args ...interface{}) (int, error) { return fmt.Fprintln(stdoutWriter, args...) }
- [23:00] 先に離れている島を繋げておけば、繋ぐたびに1点増えるなと思った. 繋げるパスを追加して提出し、49654387点をゲット. 205位.
package main import ( "bufio" "fmt" "math" "os" "strconv" ) func min(x, y int) int { if x < y { return x } return y } func fill(d [][]byte, i, j int, x, y byte) { q := [][2]int{{i, j}} for len(q) != 0 { m, n := q[0][0], q[0][1] q = q[1:] d[m][n] = x if m > 0 { if d[m-1][n] == y { q = append(q, [2]int{m - 1, n}) } } if m < N-1 { if d[m+1][n] == y { q = append(q, [2]int{m + 1, n}) } } if n > 0 { if d[m][n-1] == y { q = append(q, [2]int{m, n - 1}) } } if n < N-1 { if d[m][n+1] == y { q = append(q, [2]int{m, n + 1}) } } } } // var ( N int ) func main() { defer flush() _ = readInt() N = readInt() K := readInt() S := make([]string, N) for i := 0; i < N; i++ { S[i] = readString() } d := make([][]byte, N) for i := 0; i < N; i++ { d[i] = make([]byte, N) } result := make([][]string, 0, K) for n := 1; n <= K; n++ { x := byte(n + '0') t := make([]string, 0, 10000) for i := 0; i < N; i++ { for j := 0; j < N; j++ { d[i][j] = S[i][j] } } for i := 0; i < N; i++ { for j := 0; j < N; j++ { if d[i][j] != x { if i > 0 && d[i-1][j] != d[i][j] { s := fmt.Sprintf("%d %d %c", i+1, j+1, d[i-1][j]) t = append(t, s) fill(d, i, j, d[i-1][j], d[i][j]) } else if j > 0 && d[i][j-1] != d[i][j] { s := fmt.Sprintf("%d %d %c", i+1, j+1, d[i][j-1]) t = append(t, s) fill(d, i, j, d[i][j-1], d[i][j]) } } } } for i := 0; i < N; i++ { for j := 0; j < N; j++ { if d[i][j] != x { s := fmt.Sprintf("%d %d %c", i+1, j+1, x) t = append(t, s) fill(d, i, j, x, d[i][j]) } } } result = append(result, t) } best := math.MaxInt64 for i := 0; i < K; i++ { best = min(best, len(result[i])) } bestIndex := -1 for i := 0; i < K; i++ { if len(result[i]) == best { bestIndex = i break } } println(best) for i := 0; i < best; i++ { println(result[bestIndex][i]) } } const ( ioBufferSize = 1 * 1024 * 1024 // 1 MB ) var stdinScanner = func() *bufio.Scanner { result := bufio.NewScanner(os.Stdin) result.Buffer(make([]byte, ioBufferSize), ioBufferSize) result.Split(bufio.ScanWords) return result }() func readString() string { stdinScanner.Scan() return stdinScanner.Text() } func readInt() int { result, err := strconv.Atoi(readString()) if err != nil { panic(err) } return result } var stdoutWriter = bufio.NewWriter(os.Stdout) func flush() { stdoutWriter.Flush() } func println(args ...interface{}) (int, error) { return fmt.Fprintln(stdoutWriter, args...) }
- [23:15] 繋げるパスが上優先で、上が駄目な時に左となっていて、左が得そうな時に損なので、スコアリングして上か左か決めるように書いたが、今見るとバグっていて動作していない. でもなぜか提出したら点が増えて、49656737点をゲット. 221位.
package main import ( "bufio" "fmt" "math" "os" "strconv" ) func min(x, y int) int { if x < y { return x } return y } func fill(d [][]byte, i, j int, x, y byte) { q := [][2]int{{i, j}} for len(q) != 0 { m, n := q[0][0], q[0][1] q = q[1:] d[m][n] = x if m > 0 { if d[m-1][n] == y { q = append(q, [2]int{m - 1, n}) } } if m < N-1 { if d[m+1][n] == y { q = append(q, [2]int{m + 1, n}) } } if n > 0 { if d[m][n-1] == y { q = append(q, [2]int{m, n - 1}) } } if n < N-1 { if d[m][n+1] == y { q = append(q, [2]int{m, n + 1}) } } } } // var ( N int ) func main() { defer flush() _ = readInt() N = readInt() K := readInt() S := make([]string, N) for i := 0; i < N; i++ { S[i] = readString() } d := make([][]byte, N) for i := 0; i < N; i++ { d[i] = make([]byte, N) } result := make([][]string, 0, K) for n := 1; n <= K; n++ { x := byte(n + '0') t := make([]string, 0, 10000) for i := 0; i < N; i++ { for j := 0; j < N; j++ { d[i][j] = S[i][j] } } for i := 1; i < N-1; i++ { for j := 1; j < N-1; j++ { if d[i][j] == x { continue } a := 0 b := 0 if d[i-1][j] != d[i][j] { a++ if d[i-1][j] == d[i+1][j] { a++ } if d[i-1][j] == d[i][j+1] { a++ } } else if d[i][j-1] != d[i][j] { b++ if d[i][j-1] == d[i+1][j] { b++ } if d[i][j-1] == d[i][j+1] { b++ } } if a == 0 && b == 0 { continue } var c byte if a >= b { c = d[i-1][j] } else { c = d[i][j-1] } t = append(t, fmt.Sprintf("%d %d %c", i+1, j+1, c)) fill(d, i, j, c, d[i][j]) } } for i := 0; i < N; i++ { for j := 0; j < N; j++ { if d[i][j] == x { continue } t = append(t, fmt.Sprintf("%d %d %c", i+1, j+1, x)) fill(d, i, j, x, d[i][j]) } } result = append(result, t) } best := math.MaxInt64 for i := 0; i < K; i++ { best = min(best, len(result[i])) } bestIndex := -1 for i := 0; i < K; i++ { if len(result[i]) == best { bestIndex = i break } } println(best) for i := 0; i < best; i++ { println(result[bestIndex][i]) } } const ( ioBufferSize = 1 * 1024 * 1024 // 1 MB ) var stdinScanner = func() *bufio.Scanner { result := bufio.NewScanner(os.Stdin) result.Buffer(make([]byte, ioBufferSize), ioBufferSize) result.Split(bufio.ScanWords) return result }() func readString() string { stdinScanner.Scan() return stdinScanner.Text() } func readInt() int { result, err := strconv.Atoi(readString()) if err != nil { panic(err) } return result } var stdoutWriter = bufio.NewWriter(os.Stdout) func flush() { stdoutWriter.Flush() } func println(args ...interface{}) (int, error) { return fmt.Fprintln(stdoutWriter, args...) }
- [00:07] 上述のバグを直して提出し、49657497点をゲット. バグってなかったら2つ上がって238位だった.
package main import ( "bufio" "fmt" "math" "os" "strconv" ) func min(x, y int) int { if x < y { return x } return y } func fill(d [][]byte, i, j int, x, y byte) { q := [][2]int{{i, j}} for len(q) != 0 { m, n := q[0][0], q[0][1] q = q[1:] d[m][n] = x if m > 0 { if d[m-1][n] == y { q = append(q, [2]int{m - 1, n}) } } if m < N-1 { if d[m+1][n] == y { q = append(q, [2]int{m + 1, n}) } } if n > 0 { if d[m][n-1] == y { q = append(q, [2]int{m, n - 1}) } } if n < N-1 { if d[m][n+1] == y { q = append(q, [2]int{m, n + 1}) } } } } // var ( N int ) func main() { defer flush() _ = readInt() N = readInt() K := readInt() S := make([]string, N) for i := 0; i < N; i++ { S[i] = readString() } d := make([][]byte, N) for i := 0; i < N; i++ { d[i] = make([]byte, N) } result := make([][]string, 0, K) for n := 1; n <= K; n++ { x := byte(n + '0') t := make([]string, 0, 10000) for i := 0; i < N; i++ { for j := 0; j < N; j++ { d[i][j] = S[i][j] } } for i := 1; i < N-1; i++ { for j := 1; j < N-1; j++ { if d[i][j] == x { continue } a := 0 b := 0 if d[i-1][j] != d[i][j] { a++ if d[i-1][j] == d[i+1][j] { a++ } if d[i-1][j] == d[i][j+1] && d[i-1][j] != d[i-1][j+1] { a++ } } if d[i][j-1] != d[i][j] { b++ if d[i][j-1] == d[i+1][j] && d[i][j-1] != d[i+1][j-1] { b++ } if d[i][j-1] == d[i][j+1] { b++ } } if a == 0 && b == 0 { continue } var c byte if a >= b { c = d[i-1][j] } else { c = d[i][j-1] } t = append(t, fmt.Sprintf("%d %d %c", i+1, j+1, c)) fill(d, i, j, c, d[i][j]) } } for i := 0; i < N; i++ { for j := 0; j < N; j++ { if d[i][j] == x { continue } t = append(t, fmt.Sprintf("%d %d %c", i+1, j+1, x)) fill(d, i, j, x, d[i][j]) } } result = append(result, t) } best := math.MaxInt64 for i := 0; i < K; i++ { best = min(best, len(result[i])) } bestIndex := -1 for i := 0; i < K; i++ { if len(result[i]) == best { bestIndex = i break } } println(best) for i := 0; i < best; i++ { println(result[bestIndex][i]) } } const ( ioBufferSize = 1 * 1024 * 1024 // 1 MB ) var stdinScanner = func() *bufio.Scanner { result := bufio.NewScanner(os.Stdin) result.Buffer(make([]byte, ioBufferSize), ioBufferSize) result.Split(bufio.ScanWords) return result }() func readString() string { stdinScanner.Scan() return stdinScanner.Text() } func readInt() int { result, err := strconv.Atoi(readString()) if err != nil { panic(err) } return result } var stdoutWriter = bufio.NewWriter(os.Stdout) func flush() { stdoutWriter.Flush() } func println(args ...interface{}) (int, error) { return fmt.Fprintln(stdoutWriter, args...) }