基本情報技術者試験的な備忘録 午後 2017年(平成29年) 春 問8 アルゴリズム(最短経路)

 

アルゴリズム素人です。
基本情報技術者試験素人です。
以下違いだらけです。自分用メモ。(本格的な解説ではありません。)

 

参考問題:
基本情報技術者試験 午後 2017年(平成29年) 春 問8 アルゴリズム

(試験問題全体はここに載せていません。IPAのHPで入手できます。
ここには、問題の図1と表2とプログラムを載せておきます。)

 

問題の主旨は、出発地から目的地に至る最短経路とその距離を求めるプログラムに関する穴埋めです。

 

(最初の考え)
最短経路なので、自分だったら、全ルートを探して、その1個1個の距離を計算する。
(数が決まっていないなら再帰でもいいかも)・・・とか考えるが、このプログラムはそうではないようです。

実際に実践的に使えるプログラムなのかは分からないが、(結果から言えば)、全ルートを探す(データが増える)ようなやり方ではなく、
1個の配列(SRoute等)を更新作成していくようです。(問題にするためかなあ。うーん。)

 

**********************************************************整理
自分用memo(変数・配列)
SDist・・・最短距離を格納
SRoute・・・最短ルートを格納配列。

その他にも、
pDistは、出発地から各地点の最短を作るための配列。
pfixedは、pDistが最短の場合、trueにして確定(fix)するための配列。

さらに、
SPoint・・・出発地からの距離で最も短い地点を探し、その地点をsPointと呼ぶ。
(SDist、SRoute、SPointの頭文字Sの変数はスタートからのデータを持って結構重要。)

さらにさらに変数が出てくる。
pRoute[j]・・・しれっと出てくるが、直前の経由地点の番号
前出のpDistもそうだが、pDist[j]とかpDist[i]というように、iとjが出てくる。
これは、iが手前、jがその次みたいな使い方になっている。
(下の方に書いたが、2次元配列ではない。またプログラムの終盤では、単なるループに使っている場合もある。(プログラム46行))

newDist・・・新しいルート候補の距離((pDist(SPoint)+Distance([SPoint][j]という感じ)

その他、sp(スタート地点の番号),dp(目的地点の番号),distance(各地点間の距離等の2次元配列)(他にも変数あり。)


**************************************************************

<実際解いてみる>
で、この問題30分かけても、説明文の理解・・・
60分かけても、プログラムの理解・・・
という感じだった。プログラムの意味というか、プログラムの気持ちというか、どんな風に考えているのか分からない。
(どこに、探索したルートなどが出てくるの??とか(実は最後まで分からない))

*************************************
で、参考となる解き方をネットで探す。
Bloggerさんの
http://fe-algorithm.blogspot.com/2017/06/29s.html基本情報技術者試験 アルゴリズム問題のトレーニング方法」
を参考にトレースしてみました。感謝。
この方のは、このページしか見ていませんが、トレースがとても丁寧です。(12時間かかったと書いてあります)

結論としては、Bloggerさんの記事でいい(トレースの仕方素晴らしい)と思います。


+++++++++++++++++++++++++++++++++++++++++++++++++++相違点
ただ、
自分が間違っているのだろうけど、、
Bloggerさん4回目以降のトレースをホームページ上で割愛されているせいか、
(実際は最後までやっておられますが、問題と解答にあまり関係ないので「割愛」ということでしょう。)

プログラム40行以降、「後処理」部分(SDist、SRouteが判明箇所)ですが、
sDist = 13
とありますが、自分は14でした・・・。

pRoute[i]も、Bloggerさんは、
[0][1][2][3][4][5][6]
null0  4  0  1  5  2
に対して自分は、
[0][1][2][3][4][5][6]
null0  0  0  1  5  2
でした・・・。

これで、sRoute[j]をすると、Bloggerさんは、
[0][1][2][3][4][5][6]
 6  5  2  4  1  0  -1
に対して自分は、
[0][1][2][3][4][5][6]
 6  5  2  0       
でした・・・。

 

トレースではなく、
問題「図1」で最短のルートを考えると、
sRoute[j]が、経路の値と考えるなら、
6→5→2→0
でいいのかなと思います。
その場合の距離も、sDistが総距離と考えるなら、
3+3+8=14でいいのかなと思いましたが、
実は、6→4→1→0も
9+3+2=14なのです。(あれ?最短が2つある?)

いずれにせよ、Bloggerのトレースには感謝しています。
この記事がなかったら、もっと低レベルで終わってました。
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++

=========================================================
自分なりの解説(結果を見て、プログラムの意味を考える)・・・(ざっくりですけど)

プログラム12~39で大きなループ処理をしています。
<1回目のループ>
初期化後、1回目のループでは、地点0からの処理をしています。
SPointは0です。(出発地からの距離で最も短い地点)(同時にこの地点をpfixed)
そこから、newDistを3経路分探し、このnewDistが条件を満たす(初期値∞より短い)ので、pDistに入れます。
距離pDistが更新されたら、地点pRouteも更新します。(値0)



<2回目のループ>
SPointは1です。(出発地からの距離で最も短い地点)(同時にこの地点をpfixed)
そこから、newDistを1経路分探し、このnewDistが条件を満たす(初期値∞より短い)ので、pDistに入れます。
距離pDist
が更新されたら、地点pRouteも更新します。(値1)

このループではiとjが使われていますが、iが現在(手前)、jが次と考えていいと思います。




<3回目のループ>
SPointは3です。(出発地からの距離で最も短い地点)(同時にこの地点をpfixed)
そこから、newDistを1経路分探し、このnewDistが条件を満たす(初期値∞より短い)ので、pDistに入れます。
距離pDistが更新されたら、地点pRouteも更新します。(値3)

このpDist[j]と地点pRoute[j]ですが、同じ添え字jでも、pDist[j]は、スタートからpRoute[j]を超えた次までの総距離。
pRoute[j]は、スタート地点とpDist[j]の間であることに注意。※


<4回目のループ>(違ってたらすみません)
SPointは2です。(出発地からの距離で最も短い地点)(同時にこの地点をpfixed)
そこから、newDistを1経路分探し、このnewDistが条件を満たす(計11。先の12より短い)ので、pDistに入れます。
距離pDist
が更新されたら、地点pRouteも更新します。(値2)


ここで、3回目のループのpDist[j]と地点pRoute[j]が上書きされます。(有力候補)


<5回目のループ>(違ってたらすみません)
SPointは5です。(出発地からの距離で最も短い地点)(同時にこの地点をpfixed)
そこから、newDistを1経路分探し、このnewDistが条件を満たす(計14。初期値の∞より短い)ので、pDistに入れます。
距離pDistが更新されたら、地点pRouteも更新します。(値5)

(ここ↑、うろ覚えですが、j=6で、pDist[6]の∞を書き換えたハズ)

<6回目のループ>(違ってたらすみません)

SPointは6です。(出発地からの距離で最も短い地点)(同時にこの地点をpfixed)
この時点でpfixed[j]は、fixedされているので、newDistは作成しません。(プログラム31行)
ループを抜けます。(31~38行)




<7回目のループ>(違ってたらすみません)
(プログラム20行)i = nPointで出発地から全ての地点までの最短距離が確定で、break→大きなループのプログラム12~39も終了。


うーん。全部のルートを調べ尽くしていない・・・途中で、見限っている・・・これでいいのか?


<後処理>プログラム40~48(違ってたらすみません)
SDist・・・pDist[dp] →pDist[6]の値14(のハズ)
SRoute・・・
[0][1][2][3][4][5][6]
 6  


をループで作成していく。
ここで、問題の説明文
「(6)行番号40~48では,出発地から目的地までの最短距離を sDist に,最短経路上の地点の地点番号を目的地から出発地までの順に配列 sRoute に設定する。」
を確認。
なぜか、配列を目的地から出発地までの順にと書いてある(逆順)

これ、なんでかなと思っていたが、上記※にかいてあるように、pRouteは、スタート地点とpDist[j]の間で、端から端ではなく、端の1個手前なので、
逆順にしていかないとうまく取得できないということだろう。
(pRoute[6]は、地点5が入っている)
多分
pRouteは、
[-1][0][0][0][1][2][5]でないかな。

============================================ざっくりおしまい

************************************感想
で、結局、これ(プログラムの意味・全体像)が分かっても問題の回答にはあまり関係ない。
時間的にも無理だし。

また、どうやって解こうかと悩む・・・。

 


***********************************************************************おまけ


その他:最初のメモ
自分が、この問題でハマった点(低レベル)
・表2にiとjを使った2次元配列が出てきた。
配列Distanceと書いてあったが、プログラム中に同じようにiとjが出てきて、
そこでは、pDist[j]とか出ていて、なんで2次元の表記でないの?([i][j]とかでないの?)と考えてしまった。
(配列名が違うので、iとjを使ってもいいけど、他の変数にしてほしいです。表面上変数の数を減らした!?)
(まあ、自分が悪いのだけれど・・・)

自分が、この問題でハマった点(低レベル)
iが今。jが先?

 

+++++++++++++++++追記

自分で書きながら、やはりなんとなく腑に落ちない。やはり間違っているような気がするので、参考にしないようにお願いしやす。

 

 

20230602追記
ざっくり分かったことを書きます。
この最短経路探索は、「ダイクストラ法」とかいう、有名なものらしい。

解き方としては、各ノードに「入ってくる」線分の数だけ、ルートが考えられる。

例:地点0→地点1の場合は、距離2で確定。確定した地点から次のノードへの距離を考える。

実は、線分でなく、→矢印の有方向だとなお分かりやすい。

今回の問題は、矢印でないので、もう少し考える必要がある・・・。

ノード2では、3本線分があり、出ていく方向と思われたノード2と4について、
2→4だけでなく、4→2と考えると、
0→1→4→2→5→6
という最短13が導かれる・・・。

時間があったらまた考えよう・・・。