OUPC2023 で問題を作ってきました

はじめに

 kureha といいます。AtCoder 黄色ですが、半年ほど Rated 参加できてないのでそろそろしたい気持ちになっています。OUPC2023 Day1 大阪大学セットにて問題作成陣として参加してきました。原案を出した問題について色々書いています。

 楽しんでいただければ何よりです。

 

D - Han Burger

 ハンバーガー的な文字列を作りたいと色々試行錯誤していたところ、括弧列から定義を引っ張ってきて問題と相成りました。

 サンプルが弱いのは意図的なのですが、ペナルティがたくさん出たのは特に想定していませんでした。最初の 15 分くらい AC が出なくて冷や冷やしていました。

 

E - Han Burger 2

 原案と言っていいのかわかりませんが、出来た経緯をば。

 Han Burger を区間クエリにして文字列の長さを聞く形にしようとしたところ、その性質から vwxyz さんがこの問題を生やしました。強い人はすごい...。

 

G - Impassable Game

 問題文が長く、N - Bench と並んでそもそもあまり読まれなかった枠になるのでしょうか。やってみると案外解けるのではと思っています。

 テストケース作成は KowerKoint さん、vwxyz さん、maspy さんにお任せすることになってしまいました。(ありがとうございます)

 想定解法は O(NM/w + N^2) なのですが、python に合わせて 6sec にしたところ O(N^3/w) とかが通ったらしいです。

 

P - Score for Cutting Graph

 Day1 唯一の構築問題でした。

 着想は相加相乗平均の式から得ており、もともとは数列の並び替えでしたが、いろいろあって木を切る問題になりました。(vwxyz さんに証明していただきました。ありがとうございます)

 部分点の実装を行う → 色々実験してみる → エスパー → 満点を取るという段取りが必要な想定となっています。

 

感想

 楽しんでいただければ幸いです。ありがとうございました。

 来年も作問側で参加したいと思っているので、そのときはよろしくお願いいたします。

 

 

 

 

 

 

 

 

 

 

 卒論期間です。1文字も書けてません。

ICPC 2023 Asia Yokohama Regional に参加した

はじめに

 kureha といいます。AtCoder 黄色ですが、半年ほど Rated 参加できてないのでそろそろしたい気持ちになっています。この度 ICPC 2023 Asia Yokohama Regional に参加してきましたので、その記録を残すことにしました。

 

チーム紹介など

  • チーム名 : KSS908111314
  • チームメイト : kureha, shogo, sakasu

 チーム名は頭文字 + AtCoder のユーザー名についている数字です。

 shinchan さんに誘われて大学内の競プロサークルにお邪魔させてもらってチームを組みました。大学からコーチ含めて 10 人が横浜へ赴いたのですが、この競プロサークルにはいってないのは1人だけらしいです。

 

コンテスト当日

 ライブラリは大学の研究室で印刷したものを持ってきました。(本番では1ページも見なかった...)

 目標は上位 50%、あと mijingiri に勝ちたい。

 当初の戦略としては、PC のセットアップと AB を二人に投げて、それ以外を自分が読む感じでした。それ以降は流れで。

A 問題

 通した順に書いていきます。

 関与してない。スキップ。

F 問題

 C 以降で一番簡単で、B が WA だったようなのでやりました。実装を投げて他の問題考えた方がよかったかもしれない。

B 問題

 読んだけど分からなかったです。チームメイトが解いて自分が実装しました。実装投げてもよかったかもしれない。

K 問題

 読んだときは三分探索か?でもすり抜けるの面倒だな、とか思っていました。チームメイトが二分探索で[0, mid], [mid, 1e5] の大きい方に x 座標の中心があることを見つけてくれたので、実装しました。

 算数できないので想定解法よくわかってない。

G 問題

 チームメイトが 2人で解きました。

D 問題

 炎上しました。体感ではコンテスト時間の半分くらい取られた気がする。

  1. 何となくで問題読んで繰り返し回数が一桁しか許されないことを見逃す

  2. US 配列に慣れておらず + と = を間違える。

  3. 説明が面倒な実装ミス

 あのさぁ...

その他

 E は思い込みで解けず。まず bitDP が思いついてない(というかその前段階で勘違いしてた)のやばいけど。

 I は途中まで思いついてて無理じゃね?となっていたのを伸ばしてたら合ってたらしい。でも D 炎上したしなぁ。

結果

 全体30位で 目標の上位 50% には逆ボし、mijingiri にも負けました。

 消化不良感えぐいので来年また頑張ります。

 

 

 

 

 

 

 

 

 

 

 卒論とかいうのがあるらしい。競プロ中断した方がよくない?

 

ICPC2023国内予選に参加した

はじめに

 kureha といいます。AtCoder 黄色です。この度 ICPC2023国内予選に参加してきましたので、その記録を残すことにしました。

 

チーム紹介など

  • チーム名 : KSS908111314
  • チームメイト : kureha, shogo, sakasu

 チーム名は頭文字 + AtCoder のユーザー名についている数字です。

 shinchan さんに誘われて大学内の競プロサークルにお邪魔させてもらってチームを組みました。本来はチーム内で私が会話などを引っ張ったりするところなのでしょうが、残念ながらそんな能力はない...。

 

コンテスト当日

 ライブラリは大学の研究室で印刷しようとしたのですが、wifi がつながらず苦戦。研究室にいた同級生の力を借りて何とかなりました。(本番では1ページも見なかった...)

 自分のパソコンを使う予定だったのですが、wifiがつながっているのにコンテストサイトに繋がらず、急遽使うパソコンを変更しました。(いろいろとご迷惑をおかけしました。)

 A,B,Cをそれぞれ一人ずつ解く予定でいたのですが、印刷の都合上A,B,D を一人ずつに割り当てて、A を解いた sakasuさんが C を解くことになりました。

 

C 問題

 A,B問題は関与していないので飛ばします。

 パズル問題でした。DE問題を見ていましたが途中でやめてこちらに少し取り掛かりました。市松模様的に分けて、一方をそのまま上へ詰めて他方をそのまま下へ詰めるのかな、でもダメな部分もあるな、とか思っていたら sakasu さんが解法を持ってきてくれました。解法を聞いて行けそうだったので実装してもらいました。(ダメならダメで考えたらいいだけなので...)

 実装でなんやかんやあったようですが、ペナルティなしで AC でした。

 

D 問題

 1,2,4,8,... を持つとすべての得点を作れるので答えは 7 以下となります。なので長さ 6 以下、合計 N の広義単調増加列について考えればいいというのを思いついたのですが、時間的に速いのかが分からず、実装も面倒そうだったので後回し。E をちらっと読んで C を味見する時間へ。

 C を実装してもらっている間に E が解けたので、実装が楽そうだった E を先に解いて、その間に D の検討を shogoさんにしていただきました。

 広義単調増加列を再帰で実装しがちなのですが、長さが短く、十分速くできそうということで5重for 文を実装し、判定問題は bitsetで書いて一発 AC でした。なお途中でバグらせた模様。

 

E 問題

 ちらっと読んだときに、広義単調減少列にすればいいことには気づいたのですが、dp を思いつくのに少し時間がかかりました。dp の内容は公式解説通りなので略。C の実装でバグったらしいので、DとEを天秤にかけて E から書くことに。途中で頭が混乱したり、実装をバグらせたりなどしましたが、一発 AC。

 

その他

 A~E の 5 完を達成した後に順位表を見ると大学内1位でした。そしてF,Gを少し見ました。F は幾何とかいう苦手分野だったので見なかったことにし、G は制約が小さいなぁとか思いつつ期待値は知らない子なのでネグレクト。結果何もすることがない状態へ。

 F 問題は今考えると有限回が重要だったんですね。そのとき気づいても何もできませんが。

 

結果

 全体17位、大学内2位により国内予選突破しました。

 初遠征になるのですが不安しかないです。

 

 

 

 

 

 

 

 

 

 

 月末に院試があるのでそれまでは競プロ中断になるはず。

 

AHC020 に参加した

はじめに

 AtCoder Heuristic Contest 020 に参加してきましたので、そのときに考えたことを書き連ねています。言ってしまえばあとで見返す(かもしれない)用のメモを推敲もせずに公開しただけ。

 

初日兼最終日(15 : 00 ~ 19 : 00)

  • 初期解

5000 を n 個、1 を m 個並べる(309M 点)

 

  • 第2案

辺に関しては最小全域木で判断。

最も近い放送局が遠い家から順番に、最も近い放送局から電波が届くようにする。

411M 点。

 

 

  • 第3~6案

(ある家庭に電波が届くようにするために必要なコストの増加量)が小さい順に決定。

放送局 A から電波が届いてる家庭のうち一番遠い家庭が他の電波の範囲に入っていたら A の出力強度を下げる。

辺は最小全域木を出して、各部分木に電波を出している放送局がなければOFFにする。

 

ここまでで 470M でした。この後もいろいろやったけど点数は上がらず...

調べると最小シュタイナー木とかいうのも出てきたけど、時間もなかったし断念...

 

延長戦(19 : 00 ~)

 コンテスト終了後も提出できるのでちょっとだけやりました。

  • 最終案

実行時間が余っているので、解を複数出して最良のものを最後に出力する。

ある放送局からしか電波が届いていない家が一定以下のとき、その放送局は使わない。

辺は最小全域木を出して、各部分木に電波を出している放送局がなければOFFにする。部分木に存在する電波を出している放送局の数に応じてコストを大きくしていく。

478M 点。

左側真ん中の電波を出す放送局1つのために電波を出さない放送局を2つも経由しているのが気になりますが、自分の力ではどうしようもなさそうです...

 

 

 

AtCoder で黄色になった話

はじめに

 kureha といいます。この度 AtCoder にて入黄を果たしました。本記事はその記念に書いたものとなります。

 

自己紹介

 ・ハンドルネーム : kureha

 ・年齢 : 20 + n 歳

 ・職業 ? : 大学生

 ・競プロ歴 : 約 2 年

 ・使用言語 : C / C++

 

AtCoder 入黄

 見出しの通り、AtCoder 入黄を果たしました。

 

 黄色に到達するまでのコンテスト参加回数は 53 回、期間は約 1 年ほどとなります。競プロ全体で見ても黄色コーダーの中で見ても短い方だと思います。

 初めてのコンテスト参加が競プロの始まりだったわけではなく、以前から過去問には挑んでいました。それも含めると約 2 年くらいになります。まだまだ短い方ですかね、どうなんでしょう。

 ちなみにプログラミングに出会ってからは約 3 年になるらしいです。最初の一年間の記憶がほとんどないのですが。

 

振り返り

 レーティングを上げるために何か特別なことをしたかといわれるとそうではない気がします。基本的にはコンテストに出るなり、過去問や有志サイトの問題を解くなりしてその復習をするの繰り返しだったかと思います。

 とはいえこれだけですべて片付けるのは味気ないし、初めての色変記事でもあるし、今までのことを思い出せる限りで羅列していきます。

 

プログラミングの世界へ

 一番最初に触った言語は C です。約 3 年前、大学の講義の一つとして出会いました。あまり覚えていないのですが、当時使っていたオンライン教材を見るに基本的な知識を学んでいたようです。単純な計算方法から始まり、入力、偶奇判定、FizzBuzzを経て、最後にバブルソートと選択ソートとなっていました。

 この記事を書くために大学でやったプログラミング関係の講義を見ていたときに偶然思い出したわけなのですが、もう少しで亡き者にされるとこでした。危ない危ない。

 

競技プログラミングの世界へ

 一年後(今から約二年前)に競技プログラミング (AtCoder) と出会いました。どんなルートでたどり着いたかは覚えていませんが、『AtCoder における初めての提出』がそう言っているので間違いないです。

 AtCoder にある問題を少し解いて、二週間から一か月くらい空いて、また AtCoderを見に行くという期間が四か月くらい存在しました。このときに解いていた問題は、主に灰diff、茶diff と呼ばれる簡単なものでした。問題の難易度は AtCoder Problems という有志サイトで見ることが出来ます。むしろそれ以外の見方を知らないともいうけど。

 当時の装備は大学の講義でやったことのある内容だけで、標準的に使用可能な関数やアルゴリズムをほとんど知りませんでしたが、『ソートすることができればこの問題が解けるのに』とかは何回か思っていたようです。幸いにもソートを速く行う方法があるという知識は持っていましたが実装が分からなかったので、調べて他所からコピペして使いまわすなどしていたことは割とはっきり覚えています。今思えばこのときから『○○があれば解ける!』といった考察ができていることは結構よかったのではないかと感じていたり。

 その期間が明けた夏休み +α。それまでに比べて頻繁に問題を解くようになります。ここで C++ で提出するようになり、緑や水色の問題も少し解けるようになりました。インクルードに numeric とか alogorithm とかが追加されましたがソートしか使ってなかったような。

 

初めてのコンテスト

 2022/02/27、コンテストに初めて参加します。ABC ではなく ARC だったようです。問題 A が灰diff、問題 B が水diff で、このときの実力なら最低一問は解いて、二問目は解けたら御の字みたいな難易度でした。結果としてはペナルティを何回か出したものの最低限の一問を解き切りました。問題 B にも挑んでいたみたいですが、テストケースの一つに敗れていました。なんでダメなのかわからん、みたいなことは思っていました。当時の書いたコードを見ても何をしようとしていたかはさっぱりわかりませんでした。もしかしたら理解を諦めただけかも。

 翌々日、問題をたくさん解いたようです。常設コンテストに『アルゴリズムと数学 演習問題集』があるのですが、前半 40 問弱を一日で解いた跡が見られます。コードの中身を見てみると、(典型的な)アルゴリズムを知らないなりの工夫が見られました。アルゴリズムを知らない故に鍛えられる考察力もあるのかもしれませんね。頑張ってた自分を褒めたい。

 次の話に移るまでの約半年間、まとめて問題を解いたのはこの日ぐらいで、この後は散発的に問題を解いたようです。ARC と ABC に一回ずつ参加して茶色になりました。

 

本格的な競プロ道

 2022/08/06、この日からほとんど毎週のコンテストに参加し、本格的に競プロの道を歩くことになります。初めてレートが下がった日でもあります。2ヶ月ほどは競プロ漬でした。ちょうど大学の夏休みだったのも大きいです。

 本来であれば色ごとにやったことを分けるべきかなとも思うのですが、茶色と緑色は超特急で飛ばしてますし、水色での一か月半ほどの停滞期は毎週コンテストに出ていただけらしいので、全部まとめてここまでやっていたことを書き連ねます。

 

  • 『競プロ典型90問』をやった。

 常設コンテストの一つです。全部をやったわけではないです。知識を得るにしたって知らなければ調べようがないので、実際に問題を解いて「どういった問題があるのか」「どんなアルゴリズムやテクニックが必要なのか」を身をもって体験します。ちなみにこの理由は後付けです。

 

  • ABC / ARC 過去問を解きまくった。

 夏休みの 2ヶ月で 430 問ほど解きました。一日当たりコンテスト1,2回分と考えればそうでもないように見えると同時に暇だったんだなぁと思います。このときは終了したコンテストを適当に選んで突貫していました。過去に解いた問題を選ぶことも偶に。AtCoder Problems で過去に自分が解いた問題を見れますが、当時は知らなかった。

 

  • 鉄則本を読んだ。

 競プロにも問題集や参考書のようなものが存在します。鉄則本はそのうちの一つで、正式名称は『競技プログラミングの鉄則』です。ここに掲載されている問題は、実際に常設コンテストとして解くことが出来ます。

 大学で研究室に早期配属されたときに先生から貸し出されました。最大流・最小カット問題と二部マッチングが初知りでした。半年後、別の研究室に移動した模様。

 

  • 毎週のコンテストに出た。

 出なければレートは上がらないので、レートを上げたければ出るしかないです。

 

振り返りのまとめ

 こうして書いてみると、問題を解いて復習するの繰り返しだけで特別なにかしたわけではないなぁと思います。参考になるような点もそれほどないかな。夏休みに解いた量は異常かも?

 勉強すべきアルゴリズムやテクニックについては人それぞれでしょうし、個人的には実際に問題を解いて『こんなアルゴリズムがあれば ...!』というのを感じてみるか、著名な方の記事や本を参考にしたほうが良いと思うのでここには載せないことにします。

 ちなみに今まで解いた問題は 1303 問とのことです。

 

今後

 競プロについてはとりあえず橙を目指します。ただその前に青落ちしないといいなぁという感じです。当分は往復しそうです。黄色になった翌日に早速落ちそうでしたし。

 ICPC があるとのことで、大学の競プロサークルの力を借りて出ることにしています。ルールの都合上、ライブラリなどは印刷して写すことになるのですが、他人のコードが読めない病にかかっているため部内で作成されているライブラリがいまいちわかっていなかったりします。AtCoder ライブラリも使えなさそうなので、余所から引っ張っていたものを自分で構築しなければならなそうです。

 個人的には作問したいなぁと思いつつ、どうしたら問題が出来るのかと不思議に思う日々が続いており。数学の徒なので数式をこねたら解ける問題しか作れない...。

 

 競プロ以外について、院試があるので勉強をしなければ...。院試終わりまでは青落ちしなければ ABC はほどほどになるかと思います。卒研が終わるまでもつれ込むかも。いい研究室に入れたので何とかはなりそうです。鉄則本を貸していただいた研究室とは別のところです。

 

あとがき

 最後まで読んでいただき有難うございます。

 また次の記事でお会いしましょう。それでは。

 

 

 

AHC018参加日記

はじめに

 RECRUIT 日本橋ハーフマラソン 2023冬(AtCoder Heuristic Contest 018)に参加した際、リアルタイムで書いた日記です。ヒューリスティックに参加するのは3回目ですが、多分ランダムな解を提出しただけとかそんな感じなのでほぼ初めてのようなものです。精一杯頑張りたいと思います。

 ブログを書くのは正真正銘初めてです。間違い / 勘違いや表記揺れがかなり見られますが、日記の醍醐味ということで...

 

初日(17 : 00 ~)

 問題文を見てきました。概要としては、『岩盤を掘ってすべての家が水源までつながるようにしよう!岩盤の硬さは知らんけど』みたいな感じです。岩盤の硬さは見た感じランダム。ランダムじゃない場合は隣の岩盤がやわらかければ、この岩盤もやわらかいかも、みたいな感じです。

 この問題は『家と水源を結ぶのに必要な岩盤の数の最小値』と『岩盤を壊すために必要な回数の期待値の最小値(とそのためのパワー)』の二つを求めることになりそうです。

 とりあえず適当に実装しようと思いましたが、なんかサンプルコードが与えられているみたいなのでそれをいじって正の得点を得てきます。ほな。

 

 提出してきました。パワーが100になっているところを5000にするだけでした。ただ、サンプルコードが全部わかるような頭になっていないので、以降は自分でコードを書きます。変数に名前をつけるのが苦手なので、そこはサンプルをパクります。

 アルゴリズムコンテストのほうには入力と出力(答え)のセットが例としてついできますが、ヒューリスティックのほうにはビジュアライザというものがついてくるそうです。入力と出力を可視化できますよってことだと思います。

 ....これ表示の模様を見る限り、完全なランダムじゃないですね。運ゲー君になってしまうので当たり前といえば当たり前か...。

 このときにビジュアライザの入力に対応してプログラムを作成して提出したのですが、ビジュアライザの入力と実際の入力が異なることに気づいていませんでした。皆さんも気をつけよう!

 

 隣り合う岩盤の頑丈さにある程度の関連性があるとはいえ、一旦完全にランダムだった場合を考えます。『岩盤を壊すために必要な掘削回数の期待値の最小値(とそのためのパワー)』は C ごとに dp / 動的計画法で求め、家と水源に関しては各家から一番近い水源に最短距離で掘り進むことにします。switch文を初めて使ったのですが、そのせいでWAになりました!わーい。

 

ビジュアライズ結果 (seed = 0) , cost = 600815

 

 ペナルティとして30分間は提出できないので その間にもいろいろ考えます。何も各家と水源を直接つなげる必要はなく、その時点で出来ている道につなげば掘削回数を減らせそうです。

 この時点での絶対得点は 13,437,966 点、相対得点は 19,388,644,841 点、順位は 46 位 でした。

ビジュアライズ結果 (seed = 0) , cost = 506281

 

 ビジュアライザを見ると、色の薄いところが濃いところに比べて多く感じます。もし岩盤がやわらかいところが多いならば、完全にランダムなときより少ない体力で岩盤を壊せるかもしれません。岩盤の頑丈さの入力生成方法を元に、それぞれの頑丈さがどれくらいの頻度で現れるのかを調べてみた結果が以下です。

頑丈さ : 現れる頻度

       10 : 1520097
       20 : 78066
       50 : 21572
     100 : 10320
     200 : 5364
     500 : 2492
   1000 : 1542
   2000 : 1118
   5000 : 663

 

 ...だいぶ偏っているようです。(実際の生成方法と自分の解釈があっているという前提になりますが、)どうやら既に与えたパワーを元に今から与えるパワーを変えた方がよさそうです。変えた結果、seed = 0 のコストは 506281 -> 503302 に減少しました。

 そんなに変わりませんでしたが、一応提出します。絶対得点は 11,966,235 点、相対得点は 21,680,311,917 点、順位は 32 位 でした。結構順位が上がりました。ビジュアライザはいろんな seed 値に対して行った方がよさそうです。

 

二日目

 順位を確認してみると 70 位になっていました。

 初日はその岩盤を破壊すると決めたらすぐに破壊したのですが、破壊する岩盤を決めてから後でまとめて破壊しても同じなので、そのようにコードを変更します。

 家と水源までつながっている岩盤(水路と呼ぼう)との距離が最短になるように掘っていますが、最短になる掘り方は複数あります。なので何らかの形で評価値を求め、それに従って掘り方を決めることにします。各ルートの評価値を、そのルートで掘ったときの各家から水路までの最短距離の合計としておきます。 44位まで上がりました。やったぜ。(後日追記 : ビジュアライズ結果を撮り忘れてしまった...)

 

 今回の岩盤は、隣合う岩盤の頑丈さにはある程度の関連性が見受けられます(パーリンノイズってそういうものらしい)。硬い岩盤の隣を掘るときは最初からパワーを込めてもよさそうです。

 

 この日は以上で終わりました。実装できそうなのが思いつかなかったんだからしょうがない。

 

3日目

 二つの岩盤の距離が近ければその頑丈さもおおよそ予想できそうというのが昨日の推測でした。またスタートと目標地点さえ決めれば通るルートは自由です。ならば、少し先の地点に調査隊を送り込んで岩盤の硬さを調べてもらい、硬い岩盤を避けるようなルートを通れば消費する体力は少なくなりそうです。

 掘る道が直線であればそのまま真っすぐ進みますが、L字であれば 2 方向に調査隊を送り先に返ってきた方に進みます。

ビジュアライズ結果 (seed = 0) , cost = 380378

 画像の右下に分かりやすく調査した残骸が残っています。初日のビジュアライズ結果と見比べてみると左側の硬い岩盤を避けていることが分かります。

 いざ提出してみたら 3 個のテストケースで WA を吐きやがりました。本採点では 3000個のテストケースを処理するので 150 ~ 200 個の WA が出ます。もちろん、どこで間違っているかを探さねばなりませんが一目で分かるわけがなく...。ビジュアライズでエラーを吐く seed 値を見つけるところから始まります。6 % の旅へいざ。

 

 見つけました。右の画像は掘削地点の仮組で、左の画像は調査を行って実際に掘った岩盤です。真ん中あたりにある家から『右に行って下に進む』という処理になるはずが『下に行って水源に向かう』という処理になっています。真ん中の家の到着地点は水源になっており、あり得るルート上に他の家からの到着地点 = 合流地点があれば一旦そこに向かうのですが、合流地点が二つあったようです。各マスごとに合流地点かどうかのフラグだけを持っていたので、i 番目の道の掘削予定地かどうかのフラグを持てば判断できそうです。勝ったなガハハ。

ビジュアライズ結果 (seed = 30)

 負けました。1 個のテストケースで WA が出ました。2 % の旅か...。6 % の旅は結局 30個調べることになったので、今回は100個ぐらいでしょうか。

 

4日目 ~ 5日目

 一つ一つ出力させてビジュアライザにぶち込んでエラーメッセージが出るものを探すのが非常に面倒な作業なので、水源からDFS / 深さ優先探索を行ってすべての家にたどり着くかチェックして足りなければエラーを吐くという関数をつけました。まあ 200個調べてもエラー吐かなかったので諦めることにしますけど。

 コンテスト終了後追記 : 3日目で見つけたミスと似たようなものでした。家 A →地点 B → 地点 C → 水源 D と向かうとき、処理する順番の間違いにより地点 B に向かわなくてもよいことになっていたようです。

 

 いつの間にかコードの量が 5700 行になっていました。そのうち5000行が埋め込みなので、実質的には700行くらいです。量が多くなると整理したいのですが上手な整理の仕方が分かりません。

 そんなこんなしているうちに順位が3桁になってしまいました。次の手を考えるとしましょう。家から水路までの最短距離とそのルートを求めるダイクストラ法を用いることにします。現在いる地点からちょっと先を掘ったけど岩盤を破壊できなかった場合、該当箇所とその近辺のコストを少し上げます。そうすると別のルートを探してくれるかもしれない、という感じです。(伝わっているか不安になっているの図)

 とりあえず、やってみた結果がこちらです。

ビジュアライズ結果 (seed = 0) cost = 380378 -> 273619

 左の画像が昨日までのコードでの結果、右の画像がダイクストラ法を使った結果です。右上のほうに違いが顕著に表れています。コストも大きく減りました。いざ提出!

 

 ダメでした。以前のコードは "WA" を吐きやがったのでテストケースの絶対得点(の合計)が分からないですが、相対得点が2,000,000,000 点ほど下がっていました。順位にして50位分です。(113位 -> 169 位)

 今回のプログラムでは掘削する回数が増えてしまい、Cが大きいとコストが増えてしまうようです。そのようなときの(雑かもしれないけど効果的ではある)対処法、場合分けを試してみるとしましょう。C が小さいときはダイクストラ、大きいときは以前のプログラムという風にしてきます。これは勝ったべ。

 

 ダメでした。絶対得点は下がりましたが、相対得点も下がりました。いろいろビジュアライザを見ていると、気になるものを見つけました。

 

ビジュアライズ結果 (seed = 8) cost = 44080, 209774

 えー、右がダイクストラを使ったものです。コストが4.5倍、つまりこのテストケースの相対得点は 4.5分の1です。多分まずいです。

 おそらく、『該当箇所とその近辺のコストを上げる』という処理における近辺の範囲が小さいかったことに起因しそうです。遠回りするよりも突っ切った方が速いと思わせてしまったようです。入力生成方法的にはこの『色が濃い範囲の広さ』もテストケースごとにランダムなので、入力から伺い知ることはできません。どうにかしてきます....。

 コンテスト後追記 : 局所的に頑丈さが小さい / 大きい箇所に引っかかった結果、悪い方向へ進んでしまったものと思われます。

 

 どうにかしようとした結果 順位が 5 つだけ上がりました。焼石に水とかいうやつです。前のやつを提出しなおすことにして今日は寝ます。寝ないと口内炎が 2 つできたりとかしますから、皆さんも気を付けてください。

 

6日目 ~ 終了

 相変わらず WA が出るわ、なんか別のエラーも出始めるわでなんだかよくわかりません。尻切れトンボ感がありますが、別にやることがあるので(実質初めての)ヒューリスティックコンテストへの挑戦はここで終了することにします。無念...

 

解法

1. 準備

 頑丈さの出現頻度をだいたいで計算します。noise = randf(-1.0 , 1.0) と仮定し入力生成法に従って計算するだけです。計算しといて埋め込んでおきます。

 パワーを合計で i 与えても壊れなかったとき、次に与える最適なパワーを計算します。消費する体力の期待値が最小になるものを dp / 動的計画法で求めればよいです。

 

2. ルートの仮組

 各家から水源までのルートを仮に決めます。

 K 個の(始点, 終点, 距離)の組を持っておきます。始点は K 個の家で、終点は水が存在するマスのうち始点からの最も距離が小さいマスです。最初は最も近い水源です。

 距離が最も小さい始点と終点の組について、( x 方向に移動 -> y 方向に移動 -> x 方向に移動 ), ( y 方向に移動 -> x 方向に移動 -> y 方向に移動 ) のどちらかかなるルートのうち、K 個の距離の総和が最も近いルートを選択します。

 各マスにはどのルートが通る予定かの情報と、終点になっているかの情報を持っておきます。

 

3. 実際のルート決め

 仮組された一つのルートについて、途中に別のルートの終点がある場合は 2 つに分割します。(地点 A -> 地点 B を 地点 A -> 地点 C , 地点 C -> 地点 B に分ける。)

 (sx, sy) から(gx, gy) に向かうとします。(sx < gx, sy < gy)

 sx + a と sy + a を交互に掘って岩盤が先に壊れた方向に掘り進め、始点を更新します。gx < sx + a となる場合は最短となるルートを適当に掘ります。

 

4. 岩盤の掘り方

 最後に岩盤を掘っていきます。隣接する 4 マスのどれも掘られていない場合は準備で決めたパワーに従って掘ります。

 そうでない場合は各岩盤の頑丈さの下限と上限から推測される値の平均値で一回掘ります。C が大きいほど上限に近づけると掘り直しが少なくできそうでした。頑丈さはどれも一様に出るわけではないので準備のときに埋め込んだ値を使います。

 岩盤が壊れなかった後の一回はちょっとだけパワーを弱めて掘り、以降は準備したパワーで掘ります。

 

 最終結

 暫定テスト : 相対スコア 20,901,814,958、順位 265 位

 システムテスト : 相対スコア 1,184,581,986,143、順位 312 位 

 

 システムテストの結果が暫定テストに比べて悪くなりました。暫定テストは 50 ケースだったので、上振れ下振れが大きくなるようですね。ローカル版のビジュアライザも用意したほうが良いのかしら。機械音痴なのでこういうのよくわからないんですけど。

 それとシステムテストの方でも WA は出ていました。seed値が公開されたらその理由を探ってみたいと思います。