PAT A1030-旅行プラン(ダイクストラ)
タイトル
旅行者のマップは一緒に、各高速道路のコストで、高速道路に沿って都市間の距離を提供します。今、あなたは彼/彼女の開始都市と目的地間の最短経路を決定するために旅行者を支援するプログラムを書くことになっています。そのような最短経路が一意でない場合、あなたは一意であることが保証される最小のコスト、と一つの出力になっています。
入力仕様:
各入力ファイルには、1つのテストケースが含まれています。各ケース4つの正の整数を含む行から始まるN、M、S、およびD、N(≤500)は都市の数である(したがって、都市が0から番号付けされるNを -1)。Mは、高速道路の数です。S及びDは、それぞれ、開始および宛先の都市です。次に、M個の行の形式は、各高速道路の情報を提供し、次のとおりです。
City1 City2 Distance Cost
数字は、これ以上の500以上のすべての整数ではない、とスペースで分離されます。
出力仕様:
各テストケースのために、印刷が一列に目的地までの開始点から最短経路に沿った都市が、合計距離および経路の総コストが続きます。数字はスペースで区切る必要があり、出力の末尾に余分なスペースがあってはなりません。
サンプル入力:
4 5 0 3
0 1 1 20
1 3 2 30
0 3 4 10
0 2 2 20
2 3 1 20
サンプル出力:
0 2 3 3 40
問題解決のためのアイデア
最短経路を見つけるには、その使用ダイクストラのアルゴリズムをタイトルには第2の経路選択基準を与えたので、少し変更を行う必要があるので、総支出のパスがあり、それが最短経路は、各更新は、少しの判断を行い、裁判官であります下、ノードがパス上に少ない支出を置くならば、現在の総支出のノードは、低くもあります。
その後、ダイクストラ法に関する大まかなコードを書きます:
void Dijkstra(){
while(1){
V = 为收录顶点中dist最小者;// 也就是collected中值为false的点中具有最小距离的点
if(这样的V不存在) break;//也就是遍历完了所有的节点
collected[V] = true; // 表示这个点已经被遍历过了
for( V的每一个邻接点W ){
// 下面的判断可能没有太大需要,因为一个点如果被遍历了,那么它存留的最短路径在当前来说一定是会小于dist[V]+E的,因为W如果被遍历过,那么W就是在V之前被遍历,其最短径长度必然小于V,更不用说还要加上一个E了,所以if(dist[V]+E<v,w> < dist[W])完全足够。
if(collected[W] == false){
if(dist[V]+E<v,w> < dist[W]){// 如果邻接点通过V到达原点的距离更小,那么就更新现在的邻接点到原点的距离值
dist[W] = dist[V] + E<v,w>;
path[W] = V;// path中如此存储表示在路径上W的前一个节点是V,最后通过写个递归函数很容易可以打印出当前路径
}
}
}
}
}
コード
#include <stdio.h>
#include <vector>
using namespace std;
typedef struct{
int CityNum;
int Cost;
int Distance;
} APCITY;
typedef struct{
//apcity 与当前城市直接相连的城市。包含距离,花销,城市编号
vector<APCITY> apcity;
//当前城市是否被遍历
bool traverse;
//到当前城市的最短距离
int shortestdist;
//到当前城市的总花销
int totalcost;
} CITY;
int Path[501], leftCityNum, N;
CITY citys[501];
// 找 原点到还没遍历的点之间的距离 最短的点
int findShortestDistCity(){
int min = 1000, index = 0;
for(int i = 0; i < N; i++){
if(!citys[i].traverse && citys[i].shortestdist < min){
min = citys[i].shortestdist;
index = i;
}
}
return index;
}
void Dijkstra() {
int V, APsize, W;
// leftCityNum表明还没有被赋值给最短距离属性的City个数
for(int i = leftCityNum; i > 0; i--){
V = findShortestDistCity();
citys[V].traverse = true;
APsize = (int)citys[V].apcity.size();
for(int j = 0; j < APsize; j++){
W = citys[V].apcity[j].CityNum;
// 当前点到原点的距离+当前点到邻接点W的距离 < W之前存储的到原点的距离
if(citys[V].shortestdist + citys[V].apcity[j].Distance < citys[W].shortestdist){
citys[W].shortestdist = citys[V].shortestdist + citys[V].apcity[j].Distance;
citys[W].totalcost = citys[V].totalcost + citys[V].apcity[j].Cost;
Path[W] = V;
// 当前点到原点的距离+当前点到邻接点W的距离 == W之前存储的到原点的距离 &&
// 通过当前点到邻接点W的总花销如果比W之前那条路径的总花销小,那么就可以替换W所在的路径,也就是修改W的前一个节点为当前节点V
}else if(citys[V].shortestdist + citys[V].apcity[j].Distance == citys[W].shortestdist && citys[V].totalcost + citys[V].apcity[j].Cost < citys[W].totalcost){
citys[W].totalcost = citys[V].totalcost + citys[V].apcity[j].Cost;
Path[W] = V;
}
}
}
}
//路径打印函数
void printPath(int V){
if(V == -1) return;
printPath(Path[V]);
printf("%d ", V);
}
int main() {
int M, S, D;
scanf("%d %d %d %d", &N, &M, &S, &D);
int City1, City2, Distance, Cost;
APCITY info;
for(int i =0; i < N; i++){
citys[i].shortestdist = 1000;
citys[i].traverse = false;
citys[i].totalcost = 0;
Path[i] = -1;
}
for(int i = 0; i < M; i++){
scanf("%d %d %d %d", &City1, &City2, &Distance, &Cost);
info.CityNum = City2;
info.Distance = Distance;
info.Cost = Cost;
citys[City1].apcity.push_back(info);
info.CityNum = City1;
citys[City2].apcity.push_back(info);
}
citys[S].shortestdist = 0;
leftCityNum = N - 1;
Dijkstra();
printPath(D);
printf("%d %d\n", citys[D].shortestdist, citys[D].totalcost);
return 0;
}