数据结构/PTA-旅游规划/图/dijkstra算法
Posted elegantcloud
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构/PTA-旅游规划/图/dijkstra算法相关的知识,希望对你有一定的参考价值。
有了一张自驾旅游路线图,你会知道城市间的高速公路长度、以及该公路要收取的过路费。现在需要你写一个程序,帮助前来咨询的游客找一条出发地和目的地之间的最短路径。如果有若干条路径都是最短的,那么需要输出最便宜的一条路径。
输入格式:
输入说明:输入数据的第1行给出4个正整数N、M、S、D,其中N(2≤N≤500)是城市的个数,顺便假设城市的编号为0~(N?1);M是高速公路的条数;S是出发地的城市编号;D是目的地的城市编号。随后的M行中,每行给出一条高速公路的信息,分别是:城市1、城市2、高速公路长度、收费额,中间用空格分开,数字均为整数且不超过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
输出样例:
3 40
#include<bits/stdc++.h> using namespace std; struct { int pos; int len; int cost; } visit[520]; //起点到i点的各项数值 struct { int len; int cost; } graph[520][520]; //i点到j点的各项数值 void initgraph(int N) { for(int i=0; i<=N; i++) for(int j=0; j<=N; j++) { graph[i][j].cost=9999; graph[i][j].len=9999; } } //N M S D//城市个数,公路条数,始点,终点 void initvisit(int N,int S) { for(int i=0; i<=N; i++) { visit[i].pos=0; visit[i].len=graph[i][S].len; visit[i].cost=graph[i][S].cost; } //起点到起点本身的各项数值 visit[S].pos=1; visit[S].cost=0; visit[S].len=0; } int dij(int N,int S) { int i,j,k; for(j=0; j<N; j++) { int minpos=N; for(i=0; i<N; i++) { if(!visit[i].pos&&visit[i].len<visit[minpos].len) { minpos=i; } } if(minpos==N) break; visit[minpos].pos=1; for(int i=0; i<N; i++) { if(!visit[i].pos) { if(visit[i].len > visit[minpos].len + graph[i][minpos].len) { visit[i].len = visit[minpos].len + graph[i][minpos].len; visit[i].cost = visit[minpos].cost + graph[i][minpos].cost; } if(visit[i].len==visit[minpos].len + graph[i][minpos].len) { if(visit[i].cost>visit[minpos].cost + graph[i][minpos].cost) visit[i].cost=visit[minpos].cost + graph[i][minpos].cost; } } } } } int main() { int N,M,S,D; cin>>N>>M>>S>>D; initgraph(N); int a,b,x,y; for(int i=0; i<M; i++) { cin>>a>>b>>x>>y; graph[a][b].len=x; graph[a][b].cost=y; graph[b][a].len=x; graph[b][a].cost=y; } initvisit(N,S); dij(N,S); cout<<visit[D].len<<" "<<visit[D].cost; }
分析:单源路径最短问题
简而言之,求两地之间最短距离的路径,若有多条一样短的路径,那么再找最便宜的
如上图,是根据样例得到的图
这就是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。直接使用迪杰斯特拉(Dijkstra)算法即可:
设置辅助数组Dist,其中每个分量Dist[k]表示:当前所求得的从源点到其余各顶点k的最短路径。
一般情况下:Dist[k]=<源点到顶点k的弧上的权值>或者=<源点到其它顶点的路径长度>+<其它顶点到顶点k的弧上的权值>
其初态为:若从源点到顶点k有弧,则为弧上权值;
否则,则为∞。
1.在所有从源点出发的弧中选取一条权值最小的弧,即为第一条最短路径。 Dist[k]=v>G.arcs[v][k]v和k之间存在弧,INFINITEv和k之间不存在弧 其中的最小值即为最短路径的长度。 2. 修改其它各顶点的Dist[k]值。假设求得最短路径的顶点为u,若 Dist[u]+G.arcs[u][k]<Dist[k] 则将 Dist[k] 改为 Dist[u]+G.arcs[u][k]。 3. 在各顶点的Dist[k]中选择最小值,即为到达该顶点的最短路径。 4. 重复2,3步,直到所有顶点的最短路径都找到。
对于本题的代码:
1.定义结点和路径
不再从图的标准结构设置,直接设置两个结构体。visit[]记录结果;graph[][]相当于图的弧,里面记录下标(结点)之间的长度、费用
#include<bits/stdc++.h> using namespace std; struct { int pos; int len; int cost; } visit[520]; //起点到i点的各项数值 struct { int len; int cost; } graph[520][520]; //i点到j点的各项数值
2.初始化
void initvisit(int N,int S) { for(int i=0; i<=N; i++) { visit[i].pos=0; visit[i].len=graph[i][S].len; visit[i].cost=graph[i][S].cost; } //起点到起点本身的各项数值 visit[S].pos=1; visit[S].cost=0; visit[S].len=0; }
这里不要忘记N是城市个数,S是起点。初始化visit为源点外的其它点到源点距离,注意自己到自己的距离和费用都是0。
3.数据的输入
int N,M,S,D; cin>>N>>M>>S>>D; initgraph(N); int a,b,x,y; for(int i=0; i<M; i++) { cin>>a>>b>>x>>y; graph[a][b].len=x; graph[a][b].cost=y; graph[b][a].len=x; graph[b][a].cost=y; }
不要忘记graph[a][b]和graph[b][a]都设置上
4.核心:Dijkstra函数
int dij(int N,int S) { int i,j,k; for(j=0; j<N; j++) { int minpos=N; for(i=0; i<N; i++) { if(!visit[i].pos&&visit[i].len<visit[minpos].len) { minpos=i; } } if(minpos==N) break; visit[minpos].pos=1; for(int i=0; i<N; i++) { if(!visit[i].pos) { if(visit[i].len > visit[minpos].len + graph[i][minpos].len) { visit[i].len = visit[minpos].len + graph[i][minpos].len; visit[i].cost = visit[minpos].cost + graph[i][minpos].cost; } if(visit[i].len==visit[minpos].len + graph[i][minpos].len) { if(visit[i].cost>visit[minpos].cost + graph[i][minpos].cost) visit[i].cost=visit[minpos].cost + graph[i][minpos].cost; } } } } }
?循环n-1次,找到这n-1个点中到源点最短的点,记为minpos(minpos的初始设为N)。判断条件:① !visit[i].pos :这个i点没有被使用过/没有被加入到最短路径中 ②Visit[i].len<Visit[MinPoint].len:源点到i的距离小于源点到minpos的距离
?visit[minpos].pos=1:这个点要被加入到最小路径中,赋1
?是否存在位于源点和minpos之间的中继点,使得经过中继点的路长小于这两点直接路径的路长
是,加入那个中继点,修改数据为新的路径
?是否存在位于源点和minpos之间的中继点,使得经过中继点的路长等于这两点直接路径的路长
是,比较费用大小
以上四个语段均放置在for(int j=1; j<N; j++){}中
以上是关于数据结构/PTA-旅游规划/图/dijkstra算法的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ-3627路径规划 分层图 + Dijkstra + spfa
PTA 7-35 城市间紧急救援(Dijkstra+DFS)