Upload
yowaken
View
1.874
Download
3
Embed Size (px)
Citation preview
TopCoder Marathon Match 74
AntiTravelingSalesperson(巡回セールスマンにイヂワルしちゃえ)
書いた人: yowa (twitter @yowa)
今回の問題
巡回セールスマン問題を
最近傍巡回で解くから、
イヂワルな
点配置を考えてね!!
バックグラウンド
平面上の巡回セールスマン問題(TSP)
平面上に点がいくつか与えられるすべての点を一度ずつ訪れる合計距離を短くしたい
最近傍ヒューリスティック(nearst-neighbour: NN)
開始位置から最も近い点に移動そこから、未訪問の最も近い点に移動すべての点を訪れるまで繰り返す
今回の問題(もちょっと詳しく)
引数 点の数 N (10~1万)
Nf 個の固定点 (Nf = 3~10) ※スタート地点も指定やること
N 個の点を自由に配置する ※指定枠内でスコア
(N+Nf) 個の点を NN ヒューリスティックで解く得られた巡回路の距離がスコア長ければ長いほど良い
以降、やったこと
2通りの切り口
最適解自体が長い点配置を考える
NN が苦手な配置を考える
最適解が長い
ランダム配置は意外に長くない点間の距離がバラバラ短いのもあれば長いのもある
最適解は短い辺が採用されがち
「最も短い辺」の長さを長くすればよくね?
(最適解の長さ) (≧ 最も短い辺の長さ)×(点の数)
点を格子状に配置
縦sqrt(N)個、横sqrt(N)個最短辺の長さ: 1/sqrt(N)
最適解の長さ:
N × 1/sqrt(N)
= sqrt(N)
※ 点を置ける範囲は 1×1 の正方形
NN が苦手な配置
アルゴリズムの中の人の気持ちを想像あの点はこっちの点より微妙に遠いおだから後回しにするお!
… …あ、あれ あの点からどんどん遠ざかるお結果的に遠回りになってしまったお
点を後回しにするような配置にすればよさそうだ
格子状の点を食い残しつつ巡る
赤い点を残して回る等距離の点が複数あったときの処理返り値配列で先に出てくる方が選択される
赤い点を後ろに入れておく赤い点同士の最短距離通常の2倍
青3 個 + 赤1 個 で 1グループ
3×11×24
N=1.25N
初日 暫定トップ
一瞬でも輝いたさ!
ふて寝期
四角い格子点より三角な格子点の方が点が密点の数が同じなら、点の間隔を開けられる
だから三角格子にするとさらに点が伸びる!
でも、後回しテクは等距離なのが生きてる整数座標にしか置けないから、等距離は無理なんで√3 ……は有理数じゃないんだお
……ピタゴラスに言いつけてやるお
一週間後
微妙にズレておk ※辺長より6桁小さいズレ
b a, a s, a t ≦ ≦ ≦ なら太線ルートを通ってくれる
くらい(たぶん)
aa
a
b
bs s
s s
t t t t
23
13
3N=1.336N
あとはグダグダ
格子状配置が威力を発揮するのは大きい N
小さいNだと点配置に合わせたカスタマイズが効く
N は 10~1 ……万、とは言っても10^rand(1~4の実数乱数)
具体的には 10~20 が出る確率が全体の1割とか 小さい N がちょー重要
アイデアないですランダム配置や、ランダム点移動で山登りしたくらいランダム点移動山登りはでかいNでもやった
ちょっと頑張った方法
点配置を固定→順路が決まるp(0) → p(1) → ... → p(X) → ... → p(N+Nf) → p(0)
順路が変わらない範囲で p(X) を動かす(A) p(0) ... p(X-1) を変えない(B) p(X-1)→p(X) を変えない(C) p(X)→p(X+1) を変えない
(a) |p(i)→p(i+1)| < |p(i)→p(X)| (0 i X-2)≦ ≦(b) |p(X-1)→p(X)| < |p(X-1)→p(j)| (X+1 j N+Nf)≦ ≦(c) |p(X)→p(X+1)| < |p(X)→p(k)| (X+2 k N+Nf)≦ ≦
ガチはめんどい
連立不等式(a) は「円の内側」(b) は「直線で区切った片側」(c) は「円の外側」
…これらを満たす点集合(平面上の領域)を考え…
めんど!p(X) を基点とした縦横方向だけを考える平面上の領域→めんどい直線上の区間→まだマシ
あんまり使えてない
同一距離なら配列内順序を優先これを考慮するのがめんどくて実装バグりまくる
1 点について範囲を求めるのに O(N) かかる 全点では O(N^2) なので、おいそれと呼べない
これを使っても劇的な改善があるわけじゃない所詮「1点動かす」「ルート不変」という局所最適ですし
NN さんパネェ いぢわるしてごめん
NN を自分で実装しなきゃダメだよねN 回最近傍を探す → O(N^2)
O(N log N) ……があるらしいけど、わからん
kd-tree (2d-tree) ?知らんけど「前処理しといてその後高速」なんじゃね?「(一度訪問した)点を削除」操作もいけるんかね?パス
……どう実装したもんか
これ、Codeforcesでやったとこだ!Minimum Sum (School Regional Team Contest, Saratov, 2011) 1週間前
点集合から、最も距離が小さい点ペアを探す問題自分の解法
まず x 座標で全体をソート点pの最近傍: pとソート順が近いものから探すソート順が遠いものは探索枝刈りできる(現時点での最近傍との距離) < (x 方向の距離)
O(N^2) だけど通った今回もこの方式で行くお!
そんなに速くない
N=1万で、NN解を100回求めるのに2秒かかる解を求められる回数が、点の数Nより超少ない
……まともな山登りにならないお
点を1個動かす山登りたいていNN解は局所的にしか変わらない(気がする)
……それを利用すれば わからん
y軸でいくつかの領域に分けて、領域で現行方式N=1 万で 3 倍くらい速くなった
……でも雀の涙だね
スコアボードをながめる
自分が submit しても上位陣のスコアが動かないbest解を1つも出せてないという現実にヘコむ
crem たん一人抜け期2位に10点差とか
「小さい N のうまい方法あるんだろうな」とか思ってた
雑多なアイデア
小さいNは固定点パターンごとに埋め込み?そして埋め込み解をベースに探索、とかうまくいかなそうだから試してない
格子点方式で、固定点の近くの配置をいじる?思いついただけで試してない
時間あまるし、スライドにまとめる? それ採用! → 現在に至る
ご清聴 ありがとうございました
……ご清聴?