Conversation
| [dietpepsi - Share some thoughts](https://leetcode.com/problems/minimum-height-trees/solutions/76055/share-some-thoughts-by-dietpepsi-mjsc/) | ||
| [lc\_1000xCoder - [ Full Explanation ] BFS - Remove Leaf Nodes](https://leetcode.com/problems/minimum-height-trees/solutions/5060930/full-explanation-bfs-remove-leaf-nodes-b-4x00/) | ||
|
|
||
| まず、Minimum Height Tree を作る root は 1 つか 2 つという私の考えは正しかった。それをどう求めるのかだが、各ステップで現在の葉ノードを全て削除していって、最後に残った 1 個か 2 個のノードがグラフの一番長いパスの真ん中 -> Minimum Height Tree の root(s) になる。 |
There was a problem hiding this comment.
この1つか2つになる、というのを直接証明するのは少しむずかしいかもと思ったりしたのですが、Treeから全てのLeafを取り去る操作を繰り返し行う場合を考えるとき、仮に3つ以上Nodeがある場合、いずれかのNodeは必ず2本以上のEdgeを持つことになり(そうでないとTree全体がつながることがない)、Leafを取り去る操作を繰り返すと必ず1つか2のNodeが残るのですね。このLeafを一式取り去る行為の回数が、heightになるわけですね。
(ただ、このやり方だと、やはり必ずしも1つか2つであることは使わなくてもよいですね。最後にhightが同じになったものを取ればよいので...)
There was a problem hiding this comment.
そうか、そうすると連結成分の個数が2以上の場合はどうしますか?という追加の問いかけはできますね。
There was a problem hiding this comment.
このやり方はエレガントですが、もう少し愚直には、無向木の直径を求めて、その経路の中間と考えると素直ではないですか。
木の上でできるだけ長い経路(直径)を求めるのはできますね。ちょっとトリッキーな方法として、DFS 2回で行うというのがあります。適当な点から最も遠い点を計算し、そこから最も遠い点を計算すると、直径の両端になります。両端が求まったらその最短経路を計算して、中間を取ります。
There was a problem hiding this comment.
たしかにそうですね。半分になる中間点を見つける、というのがヒントで言いたいことだったのかもしれないと思いました。
これはお遊びですが、Geminiに3つの方法で計算する様子を可視化してもらいました。
- エレガントな方法
- 2回探索してその中間
- 1回探索して、高さが逆転するまで最も高いnodeに移動し続ける(私の初手の解法)
https://sasanquaneuf.github.io/math-toybox/apps/cs_mht.html
BFSになっているのはご愛嬌ですね。(DFSと指示をしたのですが)
|
|
||
| LeetCode 上の Hint を考えてみる。 | ||
|
|
||
| > How many MHTs can a graph have at most? |
There was a problem hiding this comment.
私はこのヒントの意図が全然わからなくて、相当強引に、一度てきとうなLeafをRootにして高さを数えさせてから、一つずつRootにするNodeをずらしていくとどうなるか、という方法で最初計算させました。(結果、そこまで遅くはないものの、60行ぐらいのとんでもないコードができてしまった...)
この方法でできるだろうという確信を得たのはこのヒントも関係なくはないのですが、それにしても、ヒントの出し方が中々難しいと思いました。
| leaves = [node for node in range(n) if degrees[node] == 1] | ||
| remaining = n | ||
| while remaining > 2: | ||
| next_leaves = [] |
There was a problem hiding this comment.
取り去る解法でコードをかくとき、私はここでnext_leavesを作らずに、
while leaves:
leaf, height = leaves.pop()
...
leaves.append((neighbor, height + 1))みたいな感じのコードを一度書いて失敗しました。(0-1-2-3-4みたいな場合に、4,3,2,1,0の順に取り去ってしまってダメ)
There was a problem hiding this comment.
引っかかった点も共有いただきありがとうございます。他の方々の感覚に触れ、また自分自身で考えるきっかけになるので助かります。
| @@ -0,0 +1,57 @@ | |||
| # Step 1 | |||
There was a problem hiding this comment.
自力で解けませんでした。
C++ で 4 * 10^8 なら TLE にならないだろうと高を括ったところ、 TLE になりました。解法が思いつかず、下記の解法を読んで解きました。難しかったです。
https://leetcode.com/problems/minimum-height-trees/