PAT 1030 Travel Plan(单源最短路径+优化Dijkstra)
来源:互联网 发布:手机磁盘清理软件 编辑:程序博客网 时间:2024/06/10 22:40
题目
https://www.patest.cn/contests/pat-a-practise/1030
题意:给出每座城市之间高速公路的长度和花费,求从给定起点到终点的最短路径并输出,若有多条最短路径,记录花费最小的那条。
解题思路
本题是单源最短路径的简单变形。不仅要考虑距离,还要考虑花费。
关于单源最短路径,详见之前的一篇博客:PAT 1003 Emergency(单源最短路径+Dijkstra)
对算法的修改如下:
- 在维护dist数组的同时,还要维护cost数组,其意义与dist基本相同。
松弛时要考虑的情况:
- 通过pos到k的距离更短
- 通过pos到k的距离相等时,花费更小。
出现上述两种情况时,要同时更新dist和cost数组。
AC代码
优先队列优化过的Dijkstra
#include <iostream>#include <cstdio>#include <queue>#include <algorithm>using namespace std;typedef pair<int, int> P; ///first是距离,second是编号const int maxn = 505, INF = 1<<27;int graph[maxn][maxn], weight[maxn][maxn];int dist[maxn], cost[maxn]; //dist、cost表示当前点距源点最短距离(花费)bool visit[maxn];int pre[maxn]; //记录前驱顶点int n, m, src, dest;void init() //用fill初始化,比memset功能更强,注意格式{ fill(graph[0], graph[0]+maxn*maxn, INF); //二维数组形式 fill(weight[0], weight[0]+maxn*maxn, INF); //一维数组形式 fill(visit, visit+maxn, false); //布尔形式 fill(dist, dist+maxn, INF); fill(cost, cost+maxn, INF);}void Dijkstra(int s) ///优先队列优化的dijkstra算法{ dist[s] = cost[s] = 0; priority_queue<P, vector<P>, greater<P> > q; //按照pair的第一个值升序 q.push(P(0, s)); while(!q.empty()) { P out = q.top(); q.pop(); int pos = out.second; //顶点编号 if (visit[pos]) continue; //从pos开始松弛 visit[pos] = true; //标记访问 for (int i = 0; i < n; ++i) { if (!visit[i] && dist[pos] + graph[pos][i] <= dist[i]) //通过pos到i路径可能会更短 { if ( dist[pos] + graph[pos][i] < dist[i] || (dist[pos] + graph[pos][i] == dist[i] && cost[pos] + weight[pos][i] < cost[i]) ) //路径更短或路径长度相等但花费更少 { pre[i] = pos; //更新前驱顶点 dist[i] = dist[pos] + graph[pos][i]; cost[i] = cost[pos] + weight[pos][i]; q.push(P(dist[i], i)); //加入更新后的路径值和顶点编号 } } } }}int main(){ scanf("%d %d %d %d", &n, &m, &src, &dest); init(); //初始化 int from, to, dis, cos; for (int i = 0; i < m; ++i) { scanf("%d %d %d %d", &from, &to, &dis, &cos); graph[from][to] = graph[to][from] = dis; weight[from][to] = weight[to][from] = cos; } Dijkstra(src); //输出路径 int path[maxn], cnt = 0, tmp = dest; while (tmp != src) { path[cnt++] = tmp; tmp = pre[tmp]; } path[cnt++] = src; for (int i = cnt-1; i >= 0; --i) printf("%d ", path[i]); printf("%d %d\n", dist[dest], cost[dest]); return 0;}
小技巧:
STL中的泛型函数fill功能比memset更强大,memset只能对字节赋值,而fill则是任何值都可以,调用规则: fill(first,last,val)
,其中first 为容器的首迭代器,last为容器的末迭代器,last为将要替换的值,注意二维数组a[x][y]的首尾迭代器要写a[0]而不是a。
未优化的Dijkstra
#include <iostream>#include <algorithm>using namespace std;const int maxn = 505, INF = 0X3f3f3f3f;int map[maxn][maxn], weight[maxn][maxn];int dist[maxn], cost[maxn]; //维护dist同时维护costint pre[maxn]; //记录前驱结点bool visited[maxn];int n;void init(){ for (int i = 0; i<n; ++i) { for (int j = 0; j<n; ++j) { map[i][j] = (i==j)? 0:INF; weight[i][j] = (i==j)? 0:INF; } visited[i] = false; pre[i] = -1; }}void dijkstra(int st){ for (int i = 0; i<n; ++i) { dist[i] = map[st][i]; cost[i] = weight[st][i]; //更新cost if (dist[i] != INF) pre[i] = st; } visited[st] = true; for (int i = 0; i < n-1; ++i) { int pos = -1, minn = INF; //找到dist当前最小值 for (int j = 0; j < n; ++j) { if (!visited[j] && dist[j] < minn) { minn = dist[j]; pos = j; } } visited[pos] = true; //标记pos被访问过 //松弛操作 for (int k = 0; k < n; ++k) { if (!visited[k] && dist[pos] + map[pos][k] <= dist[k]) { //经过pos到k的距离更短,或距离相同代价更小 if (dist[pos] + map[pos][k] < dist[k] || ((dist[pos] + map[pos][k] == dist[k]) && cost[pos] + weight[pos][k] < cost[k])) { dist[k] = dist[pos] + map[pos][k]; //更新dist cost[k] = cost[pos] + weight[pos][k]; //更新cost pre[k] = pos; } } } }}int main(){ ios::sync_with_stdio(false); int m, start, dest; cin >> n >> m >> start >> dest; init(); int t1, t2, d, w; for (int i = 0; i < m; ++i) { cin >> t1 >> t2 >> d >> w; map[t1][t2] = map[t2][t1] = d; weight[t1][t2] = weight[t2][t1] = w; //记录代价 } dijkstra(start); int along[maxn], cnt = 0; int t = dest; while (t != start) //记录所有前驱结点 { along[cnt++] = t; t = pre[t]; } along[cnt++] = start; //加入起点 for (int i = cnt-1; i >= 0; --i) cout << along[i] << ' '; cout << dist[dest] << ' ' << cost[dest] << endl; return 0;}
阅读全文
0 0
- PAT 1030 Travel Plan(单源最短路径+优化Dijkstra)
- 【PAT 1030】Travel Plan 最短路径Dijkstra
- pat 1030 Travel Plan
- PAT (Advanced Level) 1030. Travel Plan (30) Dijkstra最短路径
- 1030. Travel Plan (30)-PAT甲级真题(Dijkstra + DFS,输出路径,边权)
- PAT 1030. Travel Plan (30)(Dijkstra,最短路径的同时计算最小奥cost)
- PAT 1030 Travel Plan (30)
- PAT 1030 Travel Plan SPFA
- PAT 1030 Travel Plan dijkstra算法+双最短条件+保存最短路
- 浙大PAT 1030题 1030. Travel Plan
- Pat(Advanced Level)Practice--1030(Travel Plan)
- PAT 1030. Travel Plan
- 【PAT】1030. Travel Plan
- 1030. Travel Plan (30) - Dijkstra
- 1030. Travel Plan (30)-PAT
- 1030. Travel Plan (30) PAT
- PAT 1030. Travel Plan (30)
- PAT 1030. Travel Plan (30)
- linux基础入门之cal命令
- 更改jupyter notebook的主题颜色(theme) 包括pycharm
- Android_自定义控件之两圆点之间来回移动加载进度
- Ubuntu上安装Python 3.6
- Kotlin笔记(七)——委托属性(Delegated Properties)
- PAT 1030 Travel Plan(单源最短路径+优化Dijkstra)
- android 退出应用程序
- leetcode414. Third Maximum Number
- 退出应用程序的两种监听方式
- java5——运算符(算数运算符、关系运算符)
- Linux常用操作
- Android输入输出流
- 38. 编写函数,实现B=A+A',即把矩阵A加上A转置,存放在B中
- Matlab 使用 GPU 并行计算