癒しがほしい

猫並みにゆるく生きています

ロードバイクに乗り始めて3年になりました。その2

おはこんばんにちはー。どんこです。 この記事はCycling Advent Calendar 2019の7日目の記事です。 まだ、その1をご覧になっていない方はこちらからどうぞ。

donko110.hatenadiary.jp

自転車生活 2年目

自転車生活、というほど自転車といちゃいちゃしていませんでしたが、 週末は大体自転車で出かけていたり、たまに筑波山に登ったりしていました。

この年は比較的遠出することが多かった印象です。

四国から京都へ

心のふるさと、京都に帰りたくなったので、四国から向かうことにしました(は?)。

香川で食べたうどんも美味しかったし、徳島で徳島ラーメン食べれたし、 麺好きとしては大満足でした。

四国から本州に渡る時に淡路島を経由したのですが、 これがなかなかの良ルートでした。 風はそこそこありましたが、海を見ながら走るのはやっぱり気持ちいいですね。

f:id:donko110:20191207210521j:plain
UDON

淡路島から明石に渡って、いざ京都へ。 サイクリングロードなり川の堤防なりを乗り継いでいきました。

この時初めて淀川サイクリングロードを走ったのですが、道幅広いし路面状況もよくて走りやすかったです。 せっかくだったので、迷惑にならない程度に踏みました。

そんなこんなで京都に到着。 ちょうど日も暮れて、エモい京都の中を走ることができました。

f:id:donko110:20191207211152j:plain
たぶん河原町商店街

f:id:donko110:20191207211336j:plain
ケセラセラ

f:id:donko110:20191207211634j:plain
大吉山

AACR 2018

5月には、以前から気になっていた、「AACR アルプス安曇野センチュリーライド」に参加しました。

aacr.jp

白馬・安曇野雄大な景色を眺めながら風を切っていく心地よさは、 走ったことのある人にしかわからないことでしょう(ドヤ)。

また、このイベントはエイドが非常に充実していることで有名です。 味噌おにぎりがまあ美味しい。合わせていただいた漬物もできれば買って帰りたかったです。。。

f:id:donko110:20191207204524j:plain
味噌おにぎり

f:id:donko110:20191207204601j:plain

突撃となりの鹿島神宮

突撃してません。普通に自転車で行きました。

とにかくこの日は暑かったです。7月にもかかわらず、強烈な日差しと猛暑。 神宮内は木漏れ日が差し込む程度でしたが、漕いでいる途中でSAN値ピンチ。 シャーベットとざるそばでなんとか生き延びました。

f:id:donko110:20191207205608j:plain
鹿島神宮

f:id:donko110:20191207205640j:plain
竹やぶ

富士山 x2

この年も富士五湖と箱根に行きました。 しかし、毎回富士山を見てばかりではつまらない、ということで今年は富士山に登ってから富士・箱根に行くことにしました(は?)。

須走口の五合目から登り始めたのですが、これが思ったよりもきつい。 序盤はなんてことはないなぁ、と甘く見ていると、 周りに緑がなくなったあたりでだんだん足が重くなっていきました。 

幸い、天候は安定していて山小屋に着くまで快晴でした。 

f:id:donko110:20191207212357j:plain
でかい(でかい)

f:id:donko110:20191207212424j:plain
ご来光 直前まで小雨が降ってた

富士・箱根 2年目

2017年は本栖湖を回らず、甲府へ抜けるルートでしたが、今年は富士宮に降りるルートを取りました。 本栖湖といえば、もちろん......

f:id:donko110:20191207212922j:plain
オサツノヤツ

f:id:donko110:20191207213002j:plain
浩庵キャンプ場

他は2019年とかぶっている部分が多いので、次回に回したいと思います。

まとめ

こうしてみると、意外と県外に行っているなぁと思いました。  毎年これぐらい充実しているといいのですが。。。(実験。。。レポート。。。バイト。。。)

2019年分は次回で。それでは。

ロードバイクに乗り始めて3年になりました。その1

これは、Cycling AdventCalendar 2019の1日目の記事です。

今のところ自分しか入れていないので、ぼっちアドカレになってしまう可能性大です。 興味ある方は入れてみてください。僕が喜んで、逆立ちするかもしれません。

3年目になりました

申し遅れました。どんこです。 ロードバイクを2017年の5月に買ってから、約3年になりました。 いい機会なので、相棒と過ごした3年を写真を通じて振り返ってみたいと思います。

何せ、ぼっちアドカレ(2回目)になりそうなので、 尺を伸ばそうという、実にあくどい画策を打ち出すことにしました。

そんなわけで、この記事は3分割してお送りしようと思います。

BOTTECCHIA DUELLO

初めはカーボンバイクが欲しかったのですが、当時大学1年だった僕からすると、 相当高価なもので、うまく乗りこなせる自信もなかったので、 店長さんにおすすめされたバイクを購入することにしました。 それがBOTTECCHIAのDUELLOです。

f:id:donko110:20191201200406j:plain

ビジュアルも良かったので、即決しました。 カタログだともう少しオレンジ味のある赤だったので、 納車日に実際のバイクを見て、少し驚きました。

1年目

1年目、つまり2017年を振り返ってみます。 なんと言っても印象深いのは、北海道ツーリングでした。 景色がいいことこの上ない。

日本とは思えないほど真っ直ぐとした道が爽快感をさらに引き立ててくれました。 また、観光スポットも点々としていて、1週間旅をしてもしたりないほど魅力に溢れていました。

海沿いを走れば海鮮、内陸を走れば肉、というように食べ飽きることのないほど、グルメに満ちているというのは 他の県ではなかなかないのではないでしょうか(ディスってはいません)。

f:id:donko110:20191201200648j:plain
神威岬

f:id:donko110:20191201200554j:plain
青い池

f:id:donko110:20191201201011j:plain
帯広の豚丼

また、この年から富士五湖・箱根に行き始めました。 今年の富士五湖・箱根ツーリングについては、別でまとめたいと思います。

箱根ではひたすら上りで自分と戦い、 富士五湖ではのどかな湖の景色と富士山を眺めながら、湖畔を走る。 このバランスの良さが最高でした。

f:id:donko110:20191201201911j:plain
逆さ富士はこの年しか見れなかった

1年目は本栖湖から甲府の方に抜けました。 甲府の昇仙峡では、渓谷を横目にみながら走るという、なかなか訪れることのない道を走りました。

他は筑波山を登ったり、高尾山を登ったりしていました*1

続きは次回に。 今日はこの辺で。

*1:山しか登っていなかったのかな......?

Go Conference 2019 Autumn 参加記

おはこんばんにちは。donkoです。

10/28日に開催されたGo Conference 2019 AutumnにWantedlyスカラシップ枠として参加させていただきました。

こういった大きなイベントへの参加は初めてでしたが、Goについての濃厚な話をたくさん聞くことができ、 非常に充実した1日でした。

Go Conferenceとスカラシップ

Go Conferenceは半年に1回行われるプログラミング言語Goに関するカンファレンスです。

gocon.jp

一般参加枠などのほかに、スカラシップ枠が用意されています。 スカラシップ枠では、交通費や宿泊費が障壁となっていた遠方の学生が、 交通費・宿泊費の援助を受けながら、Go Conferenceに参加することができます。 Wantedlyさんの他に、mercariさんやMedia Doさんがスカラシップ枠を用意していました。

www.wantedly.com

Wantedlyスカラシップ枠参加者の中には当日の登壇者もいて、スカラシップ参加者のレベルの高さを思い知らされましたorz)

セッション

自分が面白い・為になったと思うセッションを紹介させていただきます。

Go GC algorithm 101

speakerdeck.com

Wantedly20卒内定のtaxioさんの発表です。

発表内容はGoにおけるガベージコレクションGC)の理論と実装についての解説でした。 わかりやすい図や考察を交えた説明で、すんなりと内容を理解できました。

自分は低レイヤーやアルゴリズムの話題が好きで、このセッションはかなり面白かったです。 特にGCアルゴリズムの内容についてと、世代別GCに関する議論は興味深かったです。 今後、どのような改善がなされていくのか注目ですね。

blog.golang.org

実装してアルゴリズムごとの性能も見たいので、今度試してみたいと思います。

OSS Performance Tuning Tips

speakerdeck.com

orisanoさんのOSSのパフォーマンスチューニングについての発表です。 チューニングする際の注意点やOSSにコミットする時に気をつけるべきことを丁寧に説明されていました。

orisanoさんが実際にパッチを送った体験談もいくつか紹介されていて、 wyhashのパフォーマンス改善をasmで頑張っていた話など、パフォーマンスチューニングの苦労がうかがえる場面もありました。

発表の中で、チューニングをするときのプロファイリングについて、いくつかのツールが紹介されていました。

GitHub - pkg/profile: Simple profiling for Go

使い方は非常に簡単で、main関数に一行差し込むだけで、関数レベルのプロファイルが取れます。

使ってみる

先ほどのpkg/profileを使ってみます。 適当なCLIのmain関数に以下を差し込みます。

defer profile.Start().Stop()

go runを実行し、プロファイルを生成します。 先ほど生成したプロファイルをgo tool pprofに渡すことでプロファイルの内容をみることができます。

go tool pprof-httpというフラグを渡すとブラウザでグラフやtopの結果を簡単にみることができます。

f:id:donko110:20191102084320p:plain
Graph1

個人開発のパフォーマンス改善にも役立つと思うので、積極的に使っていきたいです。

Goでつくるゲームボーイエミュレータ、またはブラウザでの動かし方

speakerdeck.com

bokuwebさんのGoで作成したゲームボーイエミュレータについての発表です。

実は自分もゲームボーイ(正確にはゲームボーイアドバンス)のゲーム開発をかじったことがあります。 「そういえばこんな感じだったなぁ」と、発表を聞いていくうちに記憶が呼び覚まされていきました笑。

エミュレータなので、CPUなどのハードウェアを実装しているのだろうと予想していましたが、 それはその通りで、レジスタの構造体のスライドでは一同大爆笑。

type Registers struct {
  A byte
  B byte
  C byte
  D byte
  E byte
  H byte
  L byte
  F byte
}

コードベースのテストだけでなく、ゲームボーイの挙動を可視化してテストできるようにしていたところも いいなと思いました。 タイルマップが変更されていくのを見るだけでも面白そうです。

また、GoをwasmにビルドしてWebAssemblyとしてブラウザ上で遊べるようしているところには情熱を感じました。

Gopher Boy

(意外と難しい)

スマホからゲームボーイができるって、なんかいいですよね。

パフォーマンスやファイルサイズについては改善できるかもしれないということで、今後に期待です。

ちなみに、bokuwebさんはGoを学ぶためにこのエミュレーターを作ろうと考えたそうなので、 これからGoを始める方は挑戦してみてはいかがでしょうか(笑)。

blog.bokuweb.me

Goコンパイラをゼロから作ってセルフホスト達成するまで

最後はDQNEOさんのGoコンパイラについての発表です。 もうタイトルからワクワクしますね。

Qiitaでかなり話題になっていたので、事前にどのようにしてコンパイラを作成していたのかは知っていたのですが、 DQNEOさんの情熱を直に感じることのできる発表で、終始聞き入っていました。

qiita.com

作成当時の小話をいくつか紹介してくださいました。 開発後半の自作interfaceや自作mallocの話は興味深かったですし、 panicのバグの話では会場が笑いに包まれました笑。

開発終了後に本家のGoコンパイラを読んだそうです。 自作のコンパイラと答え合わせをするかのように読んでいくと、 本家のGoの実装をより深く理解できそうですね。

自分はRui Ueyamaさんのコンパイラーブックをやりかけのままにしてしまっているので、 すきま時間を見つけて、また実装を進めていきたいです。 (いずれはGoでセルフホスト......!)

おわりに

Go Conferenceは、コンパイラなどの低レイヤーの話からゲームなどの話まで、 様々なジャンルのセッションを1日で聞くことのできる、数少ないイベントの一つだと思います。

学生であれば、スカラシップ枠などを有効活用して、臆せず参加してみましょう!

次は登壇して、Gopher人形をゲットしたいdonkoでした。

おまけ

抽選でTシャツが当たりました!やったー!Gopherかわいい!!

f:id:donko110:20191102002246j:plain
Gopher Tシャツ

入園時にもらった名札です。

f:id:donko110:20191102005020j:plain
Tofu on Fire

After Partyにも参加しました。 ご飯を食べながらTLを聞いて、お酒を飲んでいました。 最高に楽しかったです。

f:id:donko110:20191102002629j:plain
ベイスターズラガー

富士通クラウドテクノロジーズのサマーインターンに参加してきた

donkoです。

8月末から9月頭にかけての3週間、富士通クラウドテクノロジーズ(以下FJCT)の長期サマーインターンに行ってきました。

就活を意識してはいなかったのですが、 一つぐらいインターンに行きたかったのと、 単位を取らないといけなかったので応募してみたところ通りました。

fjct.fujitsu.com

応募〜当日

きっかけ

元々、アルバイトでクラウドを触ることが多かったので、インターンクラウド開発系にしようと思っていました。

せっかく夏休みを削って行くので、個人であまりできないようなことがしたい、と思いFJCTに応募しました。

応募は魔法のスプレッドシートのリンクから行いました。 

選考

Googleフォームに色々書いた気がするのですが、何を書いたのか忘れました。

確かVMやインフラ運用などの選択肢からどれをやりたいか、という質問でクラウドプラットフォーム開発を選んで、 Github, QiitaのURLを貼った気がします1

状況開始

ニフクラ触ったことがなかった2ので、まずはニフクラに慣れることからはじめようと思いました。

しかし、インターンの準備にトラブルがあったようでアカウントの配給が遅れるということだったので、 先に社員さんから今回のインターンでやることの概要の説明を受けました。

やること

ニフクラのサービスの一つにhatobaというものがあります。

今回のインターンではこれに関連して、Kubernetesサービスの開発を行うことになり、 Cluster APIのプロバイダーとしてニフクラ版を実装するという課題を扱うことになりました。 具体的にはCluster APIクラウド上にk8sクラスタを作ろう、という目標でした。

Kubernetestは触ったことしかなかったので、その内部構造についてはほとんど知りませんでした。 また、Cluster APIについても初めて聞いたので、まずは調査することから始めました。

さらに、CRDやcotroller-runtimeなど他のプロジェクトなどについても適宜キャッチアップを進めました。

Cluster API

Cluster APIkubernetes-sigsのプロジェクトの一つで、宣言的なAPIを使ってKubernetesクラスタを管理することができるプロジェクトです。

github.com

アーキテクチャは以下のようになっています。

f:id:donko110:20190908151519p:plain
Kubernetes の Cluster API について調べてみた」より

CLIツールからBootstrapというクラスタが作成され、そこにCustom ResourceとCustom Controllerがデプロイされます。 クラウド上で新しく作成したクラスタにこれらのリソースとコントローラーをデプロイすることで、クラウドk8sクラスタが作成されます。

いざ実装

環境構築も終わらせて、インターン2週目はひたすら実装をしていました。

開発を進めていくと、sigs.k8s.ioの開発速度の凄まじさを肌で感じることができました。 関連ツールが昨晩のうちにメジャーアップデートしていたり、Cluster APIにいつの間にかコミットが追加されていたりと、 k8s開発がたった今行われていることを実感できました。

実装に関しては、他のプロバイダーの実装を参考にしました。 だいたいどこも、Kubernetesの動作の処理(Reconciliation Loopなど)を外部パッケージに任せているため、 必要なインターフェースを実装していく形だったので、見通しはよかったです。

ニフクラのAPIを叩くだけかと思いきや、なかなかに実装が重たかったです3。 特にMachine Controller周りは処理が多く、デバッグ中に抜けている処理があることに気づくことが多々ありました。

最終週に動作確認とデバッグを行い、実際にクラウド上にkubectl applyしたリソースが作成された時はちょっと感動しました。

会社の雰囲気とか

インターン生の業務時間は10:00〜17:45でした。つくば住みに10:00は辛い。。。

お昼休みは12:00〜13:00で、12:00と17:45になるとチャイムが鳴ります。 初めは、きっちりしすぎでは?と思っていましたが、 作業に区切りがつくので、詰まった時に役立ちましたw

メンターさんはとても優しく、質問や相談にいつでも快く応じてくれました。 社員の皆さんも一緒にお昼ご飯に行ったり、気さくに話しかけてくださったりと終始楽しい雰囲気でした(語彙力)。

また、最終日には同じ開発部門の皆さんから拍手で見送られました。あったかい。

最後に

少し辛い時もありましたが、目標はなんとか(?)達成できたので、成果を残せてよかったかなとホッとしています。 また、k8s開発に興味を持つことができましたし、その最先端を垣間見ることができたのはいい経験だったと感じています。

3週間ありがとうございました!!

こぼれ話

Cluster APIにはBookが提供されていて、プロバイダーの作成に関する説明が書かれていました。 しかし、インターンの最終日前日にコミットが追加されていてBookが真っ白に... 1週間前にやられていたらと思うと...寒気が。

あと関連パッケージの開発もどんどん進んでいるので、バージョン管理がはちゃめちゃになって大変でした。 Go Modulesでreplaceで指定できなくもないのですが、数が多いので初めの方はこのあたりの問題解決でわちゃわちゃしていましたw

写真

ご飯

銀座の相場は1000円ぐらいでした。 昼ごはんにしてはちょっと高いですが、 築地に近いためか海鮮系のご飯も揃っていたり、 料亭のランチをいただけたりと、クオリティーも高かった印象です。

f:id:donko110:20190908162252j:plain
料亭の塩豚丼

f:id:donko110:20190908162116j:plain
俺の焼肉
f:id:donko110:20190908162222j:plain
最終日には江戸前寿司をご馳走していただきました>_<

部活

メンターさんがとてもアクティブで、いくつかの部活に参加させていただきました。

f:id:donko110:20190908162105j:plain
ボードゲーム

f:id:donko110:20190908162234j:plain
ボルダリング

f:id:donko110:20190908162208j:plain
ボルダリングの帰りに唐揚げ船をキメてきましたw

その他

f:id:donko110:20190908163225j:plain
色々貰いました


  1. 最終日に聞いた話なのですが、Githubを見て歯ごたえのある課題を用意してくださったようです…

  2. ニフクラはAWSGCPのように個人で利用することはできず、法人契約専用です

  3. 2000〜3000行は書いたと思います

SoundHound Inc. Programming Contest 2018 (春) C - 広告

問題文

atcoder.jp

概要

'.'と'#'からなるグリッドが与えられる。 以下のルールの元で出来るだけ多くの'.'を選択する時、選んだ'.'の個数を出力する。

  • 隣り合う'.'の両方を選ぶことはできない

解法

まずグリッドをグラフとみなすと、二部グラフの最大独立集合のサイズを出力すればいいことがわかります。

最大独立(安定)集合問題については、以下の記事が参考になります。

qiita.com

ウィキペディアから独立集合の定義を引用します。

グラフ理論における独立集合(どくりつしゅうごう、英: independent set)または安定集合(英: stable set)は、1つのグラフ内で互いに隣接していない頂点の集合である。すなわち、頂点の集合 V で、V の任意の2つの頂点をつなぐ辺が存在しない場合をいう。等価的に、そのグラフの各辺の高々一方の端点のみが V の元である。独立集合の大きさとはその中の頂点の個数である。

独立集合 - Wikipedia

ここでは、'.'をグラフの頂点とみなすことで、「互いに隣接していない頂点集合」というのが、今回の問題の条件を満たしています。

ということで、二部グラフの最大独立集合のサイズを求めるには以下の等式を用います。 蟻本に載っています。

(孤立点のないグラフに対し、)|最大安定集合| + |最小点カバー| = |V|

最小点カバー問題は最大マッチング問題に帰着できるので、

|最大安定集合| + |最大マッチング| = |V|

|V|G(V, E)の頂点のサイズです。

よって、あとは二部グラフの最大マッチングのサイズが分かればこの問題を解くことができます。

二部グラフの最大マッチング問題は最大フロー問題に帰着できるので、最大フローを求めても良いのですが、ここでは、増加路を使ったアルゴリズムで解きたいと思います。

増加路については以下の記事が参考になります。

二部グラフのマッチング [いかたこのたこつぼ]

この記事の定義を引用させていただきますと、増大路とは、以下のようなパスです。

  • 既にマッチングMがある (マッチング: ペアとなる2頂点を結ぶ辺の集合)
  • ペアのいない( Mのどの辺の端点にも含まれない)A側の点 a_iを始点とする
  • Mに含まれない辺」と「含まれる辺」を交互に辿る
  • ペアのいない(Mのどの辺の端点にも含まれない)
  • B側の点 b_kを終点とする

図で表すと以下のようなグラフで、オレンジと緑の辺を交互に用いるパスが増加路です。 緑色の辺はMに含まれている辺で、オレンジ色の辺はMに含まれていない辺で増加路に含まれる辺です。

f:id:donko110:20190510131817p:plain

さて、この増加路のオレンジの辺と緑の辺の色を反転させると、Mの大きさを1増やすことができます。

これを増加路が見つからなくなるまで繰り返すことで、大きさが最大のMを見つけることができます。

これで最大マッチングが求まったので、この問題が解けました。

提出

// 入力
int R, C;
char c[41][41];

//  ------------------------------------------
// 最大マッチング
int match[3000], d[41][41];
bool used[3000];
vii g[3000];
int vertex;

void add_edge(int x, int y) {
  g[x].pb(y);
  g[y].pb(x);
}

bool dfs(int v) {
  used[v] = true;
  for (auto u : g[v]) {
    int w = match[u];
    if (w < 0 || !used[w] && dfs(w)) {
      match[v] = u;
      match[u] = v;
      return true;
    }
  }
  return false;
}

int bipartite_matching() {
  int res = 0;
  memset(match, -1, sizeof(match));
  rep(v, 0, vertex) {
    if (match[v] < 0) {
      memset(used, false, sizeof(used));
      if (dfs(v)) res++;
    }
  }
  return res;
}
//  ------------------------------------------

signed main() {
 cin.tie(0);
 ios::sync_with_stdio(false);
  cin >> R >> C;
  rep(i, 0, R) rep(j, 0, C) cin >> c[i][j];
  rep(i, 0, R) rep(j, 0, C) {
    if (i+1 <= R && c[i][j] == '.' && c[i+1][j] == '.') {
      add_edge(d[i][j], d[i+1][j]);
    }
    if (j+1 <= C && c[i][j] == '.' && c[i][j+1] == '.') {
      add_edge(d[i][j], d[i][j+1]);
    }
    if (c[i][j] == '.') vertex++;
  }
  cout << vertex - bipartite_matching() << endl;
  return 0;
}

Submission #5326665 - SoundHound Inc. Programming Contest 2018 (春)

感想

グラフ系の問題、やんなんとなぁ。

AtCoder Beginner Contest 115 D - Christmas

全完やったああああ!(初めてかもしれない) AGCも頑張るぞおおお(白目)

問題

beta.atcoder.jp

多次元バーガーは以下のようなものです。

  • レベル0バーガーとは、パティ1枚である。
  • レベルLバーガー(L\geq1)とは、バン1枚、レベルL-1バーガー、パティ1枚、レベルL-1バーガー、バン1枚、をこの順にしたから積み重ねたものである。

レベルNバーガーを作ったときに、下からX枚を食べると、何枚のパティを食べることができるか。

解説

レベルLバーガーの構成は以下のようになる。

f:id:donko110:20181208233500p:plain

ここで、Xがどこまで伸びているかによって食べられるパティの枚数は変わってくるので、場合分けして枚数を数えてみる。

レベルLで食べることのできるパティの枚数をP_Lとすると、以下のように場合分けできる。

  • Xが真ん中のパティより上もしくは同じ位置の時

f:id:donko110:20181208234549p:plain

P_L = (P_{L-1} + 1) + (真ん中のパティより上側のレベルL-1バーガーで食べることのできるパティの枚数)

  • Xが真ん中のパティより下の時

f:id:donko110:20181208234603p:plain

P_L = (レベルL-1バーガーで食べることのできるパティの枚数)

後はそれぞれのレベルについて食べられるパティの枚数を、その時のXに応じて数え上げると答えが求まる。

ここで、レベルL-1バーガーを食べる時も、同様に数え上げることができるので、レベルNバーガーを下からX枚食べた時のパティの枚数を数えることができる。

ただし、端のバンや、終了条件を注意して実装する必要がある。

提出

(書き直してないので、汚いです。ごめんなさい。。。)

beta.atcoder.jp

感想

全完はうれしかった。誰か褒めてくれると喜びます。

ちなみに本番はこんな感じだったよ。

同じことを繰り返すだけなので、再帰で書いてもループで書いても大差ないと思うけど、バーガーの構成が再帰的になってて綺麗だから、再帰で書きたくなる。

バグる

∑(O_O;)

ミスに気付く

バグる

Σ┌( ┐*)┐

...

みたいなことを8回繰り返しました...(あほすぎる)

モチベーション上がってきたので、競プロ頑張りゅ~ (ゆるキャンの物販行ってきたのでバイアスがかかっています)

CODE FESTIVAL 2016 Final C - Interpretation

解法

ある人とある人の間に辺が貼ってあるか、ある人とある人が連結であることがわかればよい。ここで、UnionFindを使いたい気持ちになるので、どうにか使えないか考える。

ここでは、問題の入力例1を元に考えることにする。

f:id:donko110:20181206111118p:plain


この図を縦に見ると、ノードが同じ言語に並んでいる場合は、一つ目の条件である「2人ともが話すことの出来る言語が存在する」を満たしている。

また、1人目が3人目とコミュニケーションを取るためには、2人目を経由する必要があるが、これは図で表すと次のようになる。

f:id:donko110:20181206122240p:plain

赤色の矢印の両端の人はコミュニケーションができる。水色の矢印の両端はXが話せる言語である。
この時、AとBがXを経由してコミュニケーションを取ることができる時、AとBにパスが存在する。


水色の矢印については、同じ人がコミュニケーションを取ることができるとみなせるので、統合する必要はない(自己ループは考えない)。
赤色の矢印については、両端の人でコミュニケーションを取ることができるので、両端の人を統合し、一つのグループを作る。

あとは、N人の参加者が同じグループに入っているかを調べれば、全ての参加者とコミュニケーションを取ることができるかを調べられるので、この問題が解ける。

おわりに

UnionFindの練習にはちょうどいいかも。