アルゴリズムの単純なバージョンのアイデアは次のとおりです。
- 頂点(滞在できる場所) とエッジ(できる散歩)のリストを定義する
- すべての頂点には、それを他の頂点に接続するエッジのリストがあります
- すべてのエッジ ストアのウォーク長
- すべての頂点に対して、「ここまでの距離」という意味の 1000000000 のフィールドを格納します
- 開始点だけで初期化された「アクティブな」頂点のリストを作成する
- 開始頂点の徒歩距離フィールドを 0 に設定します (ここにいます)
検索アルゴリズムは次のように進みます。
- (a)「アクティブなリスト」から最低の頂点を選択し
walk_distance
、リストから削除します
- 頂点が目的地の場合は完了です。
それ以外の場合は、その頂点の各エッジについて、other_vertex
asまでの徒歩距離を計算します。
new_dist = vertex.walk_distance + edge.length
新しい距離がより短いかどうかを確認other_vertex.walk_distance
し、この場合は新しい値に更新other_vertex.walk_distance
し、その頂点がまだそこにない場合は「アクティブリスト」に入れます。
- 1から繰り返す
アクティブ リスト内のノードを使い果たし、目的の頂点を処理しなかった場合は、開始頂点から目的の頂点に到達する方法がなかったことを意味します。
C++ のデータ構造については、次のようなものを使用します
struct Vertex {
double walk_distance;
std::vector<struct Edge *> edges;
...
};
struct Edge {
double length;
Vertex *a, *b;
...
void connect(Vertex *va, Vertex *vb) {
a = va; b = vb;
va->push_back(this); vb->push_back(this);
}
...
};
n
次に、入力から、レベルには2*n
必要な頂点 (各フロアの左側と右側) と2*(n-1) + n
必要なエッジ (階段ごとに 1 つ、フロアウォークごとに 1 つ) があることがわかります。
最後のフロアを除く各フロアには、3 つのエッジを構築する必要があります。最後のフロアには 1 つだけです。
また、最初にすべてのエッジと頂点をベクトルに割り当て、後でポインターを修正します (構築後のセットアップはアンチパターンですが、再割り当ての問題を回避し、物事を非常にシンプルに維持するためです)。
int n = number_of_levels;
std::vector<Vertex> vertices(2*n);
std::vector<Edge> edges(2*(n-1) + n);
for (int i=0; i<n-1; i++) {
Vertex& left = &vertices[i*2];
Vertex& right = &vertices[i*2 + 1];
Vertex& next_left = &vertices[(i+1)*2];
Vertex& next_right = &vertices[(i+1)*2 + 1];
Edge& dl_ur = &edges[i*3]; // down-left to up-right stair
Edge& dr_ul = &edges[i*3+1]; // down-right to up-left stair
Edge& floor = &edges[i*3+2];
dl_ur.connect(left, next_right);
dr_ul.connect(right, next_left);
floor.connect(left, right);
}
// Last floor
edges.back().connect(&vertex[2*n-2], &vertex[2*n-1]);
注: テストされていないコード
編集
もちろん、このアルゴリズムは、頂点とエッジのセットが任意である (ただし、長さが負でない) はるかに一般的な問題を解決できます。
非常に具体的な問題については、はるかに単純なアルゴリズムが可能です。これは、データ構造さえ必要とせず、代わりに入力を読み取りながらその場で結果を計算できます。
#include <iostream>
#include <algorithm>
int main(int argc, const char *argv[]) {
int n; std::cin >> n;
int l=0, r=1000000000;
while (--n > 0) {
int a, b, c; std::cin >> a >> b >> c;
int L = std::min(r+c, l+b+c);
int R = std::min(r+b+a, l+a);
l=L; r=R;
}
int b; std::cin >> b;
std::cout << std::min(r, l+b) << std::endl;
return 0;
}
このソリューションの考え方は非常に単純です。
l
変数はwalk_distance
床の左側の
r
変数はwalk_distance
右側の
アルゴリズム:
初期化l=0
しr=1000000000
、左側にいるように
すべての中間ステップで、3 つの距離を読み取ります。
a
左下から右上への階段の長さ
b
床の長さです
c
は、右下から左上への階段の長さです
walk_distance
次のフロアの左側と右側を計算します
L
r+c
との間の最小値ですl+b+c
(右側から上に行くか、左側から最初にそこに行きます)
R
l+a
との間の最小値ですr+b+a
(左から開始するか、右から開始して最初に床を横切ります)
最後のステップでは、最後のフロアを横切っr
てそこから来るまでの最小値を選択する必要がありますl