07-図6観光計画(25ポイント)
自動運転の移動ルートマップを使用すると、都市間の高速道路の長さと高速道路に課金される料金がわかります。次に、相談に来た訪問者が出発地と目的地の間の最短経路を見つけるのに役立つプログラムを作成する必要があります。最短のパスが複数ある場合は、最も安価なパスを出力する必要があります。
入力フォーマット:
入力の説明:入力データの最初の行は、4つの正の整数N、M、S、およびDを示します。ここで、N(2≤N≤500)は都市の数です。ちなみに、都市番号は0〜( N-1); Mは高速道路の数、Sは出発地の都市番号、Dは目的地の都市番号です。後続のM行では、各行は高速道路に関する情報を提供します。つまり、City 1、City 2、高速道路の長さ、通行料の金額で、中央がスペースで区切られています。数値はすべて整数で、500を超えません。ソリューションの存在を確認するために入力してください。
出力形式:
パスの長さと合計料金が1行に出力されます。数値はスペースで区切られ、出力の最後に余分なスペースを入れることはできません。
入力例:
4 5 0 3
0 1 1 20
1 3 2 30
0 3 4 10
0 2 2 20
2 3 1 20
出力例:
3 40
単一のソース
からの最短経路の問題を解決します。最短経路に加えて、これに基づいて最も安価な経路を取得する必要があります。
ダイクストラアルゴリズムは、単一のソースの最短経路に
使用されます。ダイクストラアルゴリズムを使用すると、隣接行列表現グラフがより便利になります。
非常に多くの構造関数を設定するのは遅いですが、コードのデバッグと変更は速くなります;
1.グラフ構造
を設定して、距離とコストの2つのメンバー変数を使用して、頂点を道路タイプに変更します
#include<iostream>
using namespace std;
typedef struct road Vertex;
typedef int weighttype;
#define MAX 501
#define INFINITY 65533
struct road{
int distance;
int cost;
};
typedef struct GNode *ptrtoGNode; //图结构
struct GNode{
int Nv; //节点数
int Ne; //边数
Vertex G[MAX][MAX]; //存放500个序号
int start;
int end;
};
typedef ptrtoGNode MGraph;
2.グラフ関数を初期化します
MGraph CreateGraph(int n)
{
MGraph Graph = new struct GNode;
Graph->Nv=n;
Graph->Ne=0;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
Graph->G[i][j].cost=INFINITY;
Graph->G[i][j].distance=INFINITY;
}
return Graph;
//距离全部初始化为最大值
}
3.サイド構造
typedef struct ENode * ptrtoENode;
struct ENode{
//边结构
int V1;
int V2;
weighttype distance;
weighttype cost;
};
typedef ptrtoENode Edge;
4.グラフをエッジ
に挿入するための関数標準の無向グラフ補間
void InsertEdge(MGraph Graph,Edge E)
{
Graph->G[E->V1][E->V2].cost=E->cost;
Graph->G[E->V1][E->V2].distance=E->distance;
Graph->G[E->V2][E->V1].cost=E->cost;
Graph->G[E->V2][E->V1].distance=E->distance;
}
5.構築機能
MGraph BuildGraph()
{
int N,M,S,D;
cin>>N;
//s出发,d停止
MGraph Graph= CreateGraph(N);
cin>>Graph->Ne>>Graph->start>>Graph->end;
if(Graph->Ne!=0)
for(int i=0;i<Graph->Ne;i++)
{
Edge E=new struct ENode;
cin>>E->V1>>E->V2>>E->distance>>E->cost;
InsertEdge(Graph,E);
}
return Graph;
}
上記コード入力操作を、図を構築し、
MGraphグラフを保存するために確立することができる。
次に、図ダイクストラと出力関数で処理し、
注意事項
ダイクストラ関数は常に未処理のプロセスに最小距離を得る;
必要な機能FindMinDist 、sから始まる最短距離のeのインデックスを取得します。すべての宛先が処理されている場合は、ERROR値-1を返します。
int FindMinDist(MGraph Graph,int dist[],int collected[])
{
int MinV,V; //下标
int MinDist = INFINITY;
for(V=0;V<Graph->Nv;V++)
{ //未收入且小于当前最小值
if(collected[V]==false && dist[V]<MinDist)
{
MinDist = dist[V];
MinV=V; //保存下标
}
}
if(MinDist<INFINITY)
return MinV;
else return -1;
}
Dijkstra関数
最初にdistリストを初期化し、sから各都市への最短距離を示します。
次に、コストを初期化して、sから各都市への最短距離のパスに描かれたお金を示します。
次に、パスを初期化して、各都市へのsを示します。最短距離パス
。distはラインsの各要素の距離に初期化されます。ボーダレスはINFINITYです。
コストはラインsの各要素のコストに初期化されます。ボーダレスはINFINITYです。
初期の開始距離とコストは両方とも0であるため、自分までの距離は0、コストは0です。
開始点が収集されます。
サイクルを開始します
。sラインでトラバースされていない都市のインデックスを取得します。
都市に収入
を与えます。都市から各Sラインの都市までの距離を循環します。
別の都市の場合含まれて
おらず、2つの間の距離が<INFINITY(エッジあり)である場合:1.負のエッジであるかどうかを判断します-負のエッジは最小値を計算できないため、終了に失敗します(この質問では使用されません)。
if(dist[V]+Graph->G[V][i].distance<dist[i])
VスルーViの側からの最短距離S iはiが電流よりも小さい距離までの距離である:I更新距離が
費やされるお金を更新する必要があり、パス(この問題のパスが保存されていない)
距離が等しい場合-より費用小さいが更新もされている。
bool Dijkstra(MGraph Graph, int s,int e) //S为起点
{ //传入图,dist为距离列表,path为路径,s为节点
int collected[MAX]; //表示放入的结点
int V;
int dist[MAX];
int cost[MAX];
int path[MAX]; //保存路径
for(int i=0;i<Graph->Nv;i++)
{
dist[i]=Graph->G[s][i].distance; //距离
cost[i]=Graph->G[s][i].cost;
if (dist[i]<INFINITY)
path[i]=s; //i的上一个为s
else
path[i]=-1; //没有路
collected[i]=false;
}
dist[s]=0; //起点收入集合
cost[s]=0;
collected[s]=true;
while(1)
{
V=FindMinDist(Graph,dist,collected);
if(V==-1)
break;
collected[V]=true;
for( int i=0;i<Graph->Nv;i++)
if(collected[i]==false && Graph->G[V][i].distance<INFINITY){
if(Graph->G[V][i].distance<0)
return false; //有负边——失败
if(dist[V]+Graph->G[V][i].distance<dist[i])
{
dist[i]=dist[V]+Graph->G[V][i].distance; //更新dist[i]
cost[i]=cost[V]+Graph->G[V][i].cost;
path[i]=V;
}
//如果距离相等,花费更小;
if(dist[V]+Graph->G[V][i].distance==dist[i]&&cost[V]+Graph->G[V][i].cost<cost[i]){
dist[i]=dist[V]+Graph->G[V][i].distance; //更新dist[i]
cost[i]=cost[V]+Graph->G[V][i].cost;
path[i]=V;
}
}
} //while 结束
cout<<dist[e]<<" "<<cost[e]<<endl;
return true;
}
主な機能
int main()
{
MGraph Graph= BuildGraph();
bool t = Dijkstra(Graph,Graph->start,Graph->end);
}
偶然にも、floydアルゴリズムを作成しました。
構造仕様のため、複雑さが高すぎるため、main関数とfloyd関数を変更するだけで済みます。
void Floyd(MGraph Graph,Vertex D[][MAX]){
for(int i=0;i<Graph->Nv;i++)
for(int j=0;j<Graph->Nv;j++)
D[i][j]=Graph->G[i][j];
for(int k=0;k<Graph->Nv;k++)
for(int i=0;i<Graph->Nv;i++)
for(int j=0;j<Graph->Nv;j++)
{
if(D[i][k].distance+D[k][j].distance<D[i][j].distance)
{
D[i][j].distance = D[i][k].distance+D[k][j].distance;
D[i][j].cost = D[i][k].cost+D[k][j].cost;
}
if(D[i][k].distance+D[k][j].distance==D[i][j].distance
&&D[i][k].cost+D[k][j].cost<D[i][j].cost)
{
D[i][j].distance = D[i][k].distance+D[k][j].distance;
D[i][j].cost = D[i][k].cost+D[k][j].cost;
}
}
}
//此时
void output(MGraph Graph)
{
Vertex D[MAX][MAX];
Floyd(Graph,D);
//此时D存放最短distance和最短cost;
cout<<D[Graph->start][Graph->end].distance<<" "<<D[Graph->start][Graph->end].cost;
}
//
int main()
{
MGraph Graph=BuildGraph();
output(Graph);
}
まとめ
同じ距離の場合、この問題は追加のコスト判断を追加します;
ダイクストラアルゴリズム:(負のエッジがある場合、失敗します)(グラフ-> G [V] [W] <0)
収集されたリストが必要な場合、見つかった最小値を保存します値のポイント。
現在のポイントから他のポイントへの最短パスを保存するには、distリストが必要です。INFINITYに初期化されます
。Sからvへの最短パスを計算する方法は次のとおりです。
for(int i=0;i<Graph->Nv;i++)
if(dist[i]+Graph->G[i][V] < dist[V]) dist[V]=dist[i]+Graph->G[i][V] ;
複雑度はO(N ^ 2)であり、これは最小値の複雑度を見つけることです。
最小ヒープが使用されている場合は、O(NlogN)に減らすことができます。
フロイドのアルゴリズム:(負リング障害)(J == I && D [I] [J] <0)が負バック回転である場合
、グラフの隣接マトリックスを得表さ; 無限INFINITYは、最大値に初期化されます。
これに基づいて、2ポイントごとの最短距離を取得します。
収集されたリストはありません
for(int k=0;k<Graph->Nv;k++)
for(int i=0;i<Graph->Nv;i++)
for(int j=0;j<Graph->Nv;j++)
if(D[i][k]+D[k][j]<D[i][j])
D[i][j]=D[i][k]+D[k][j];
D [n] [n]をスキップして最小値0に到達するまで呼び出す
場合、2点ごとの最小値を取得するトリプルループ、動的プログラミングによる最適なサブ問題の継承、
複雑さO( N ^ 3);
コストを計算する必要がある場合は、ダイクストラアルゴリズムでコストのリストを追加し、開始点から他の点までコストを節約する必要があります。
観光計画の問題の一般化:
必要な最短経路はいくつありますか?
count [s] = 1;
aさらに短絡が見つかった場合:count [W] = count [V] ; WとVは1つのエッジだけ離れているため、同じです;
an等しい長さのパスが見つかった場合:count [W] + = count [V] ;出現するパスの数は、Wの前のポイントでのパスの数です;
エッジの数が最も少ない最短パスpath
count [s] = 0; 0
見つかった場合さらに短絡:カウント[W] =カウント[V] +1;
an等しい長さのパスが見つかった場合:カウント[W] =カウント[V] +1;