PAT 1030 Travel Plan (30)
来源:互联网 发布:2016淘宝联盟使用教程 编辑:程序博客网 时间:2024/06/05 22:33
A traveler's map gives the distances between cities along the highways, together with the cost of each highway. Now you are supposed to write a program to help a traveler to decide the shortest path between his/her starting city and the destination. If such a shortest path is not unique, you are supposed to output the one with the minimum cost, which is guaranteed to be unique.
Input Specification:
Each input file contains one test case. Each case starts with a line containing 4 positive integers N, M, S, and D, where N (<=500) is the number of cities (and hence the cities are numbered from 0 to N-1); M is the number of highways; S and D are the starting and the destination cities, respectively. Then M lines follow, each provides the information of a highway, in the format:
City1 City2 Distance Cost
where the numbers are all integers no more than 500, and are separated by a space.
Output Specification:
For each test case, print in one line the cities along the shortest path from the starting point to the destination, followed by the total distance and the total cost of the path. The numbers must be separated by a space and there must be no extra space at the end of output.
Sample Input4 5 0 30 1 1 201 3 2 300 3 4 100 2 2 202 3 1 20
Sample Output
0 2 3 3 40Hint:
先用Djikstra算出最短路径,纪录下相同的最短路径,再回溯计算花费最少的路径。
代码如下:
#include<iostream>#include<queue>#include<algorithm>#include<functional>#include<cstdio>using namespace std;const int MAXV = 1000;//最大顶点数const int INF = 0x7fffffff;typedef pair<int, int> P;//first是最短距离,second是顶点的编号(这是不仅仅是指最短距离,也指最小花费)struct edge{ int to; int dis; int cost;};//采用邻接表表示,所以这样计算int V;vector<edge> G[MAXV];//图的邻接表表示法int d[MAXV];//s到各个点的最短距离,距离数组int pre[MAXV];//最短路中的上一条边,路径数组int cost[MAXV];//花费数组bool mark[MAXV];//判断是否属于K集合void init(int n)//初始化{ for (int i = 0; i <=n; i++) { G[i].clear(); }}void dijkstra(int s){ //通过指定greater<P>参数,堆按照first从小到大的顺序取出值 priority_queue<P,vector<P>,greater<P> > que; fill(d, d + V, INF); fill(pre, pre+V, -1); fill(mark, mark + V, false); d[s] = 0; que.push(P(0,s)); while (!que.empty()) { P p = que.top(); que.pop(); int v = p.second; mark[v] = true; cost[s] = 0; for (int i = 0; i < G[v].size(); i++) { edge e = G[v][i]; int t = e.to; if (mark[t])//顶点已经在集合K中 continue; //比较大小时,将距离相同但花费更短也作为更新的条件之一 if (d[t]>d[v] + e.dis || (d[t] == d[v] + e.dis&&cost[t] > cost[v] + e.cost)) { d[t] = d[v] + e.dis; cost[t] = cost[v] + e.cost; pre[t] = v; que.push(P(d[t], t)); } } }}vector<int> get_path(int t)//到顶点t的最短路{ vector<int> path; for (; t != -1; t = pre[t]) { path.push_back(t); } reverse(path.begin(),path.end()); return path;}int main(){#ifdef ONLINE_JUDGE#else freopen("D:\\in.txt", "r", stdin); freopen("D:\\out.txt", "w", stdout);#endif int n(0), m(0); int S(0), T(0);//起点,终点 while (scanf("%d%d%d%d", &n, &m,&S,&T) != EOF) { V = n; init(V); while (m--) { int a(0), b(0), c(0), cost(0); scanf("%d%d%d%d",&a,&b,&c,&cost); edge e; e.to = b; e.cost = cost; e.dis = c; G[a].push_back(e); e.to = a; G[b].push_back(e); } dijkstra(S); vector<int> path = get_path(T); vector<int>::iterator it; for (it = path.begin(); it != path.end(); it++) { printf("%d ", (*it)); } printf("%d %d\n", d[T], cost[T]); } return 0;}
另外一种写法:
#include <iostream> #include <vector> #include <algorithm> #include <fstream> using namespace std;struct node{ int index; int curDist; vector<node> preCity;//当前结点的前一个结点,可能有重复路径,所以用vector存储前一个结点的所有值 node(int c, int d) : index(c), curDist(d) {}};const int MAXINT = 0x7fffffff;int n, m,d,s;vector<vector<int>> dist;vector<vector<int>> cost;//图中两个结点之间的花费vector<node> v;//图中所有结点的集合vector<node> q;//已求得最短路径的集合vector<int> result;int totalCost = MAXINT;bool cmp(const node &n1, const node &n2){ return n1.curDist > n2.curDist;}bool cmp1(const node &n1, const node &n2){ return n1.index < n2.index;}void Dijkstra(){ for (int i = 0; i < n; i++) v.push_back(node(i, MAXINT)); v[s].curDist = 0; while (!v.empty()) { make_heap(v.begin(), v.end(), cmp);//把当前路径最小的放到堆顶 pop_heap(v.begin(), v.end(), cmp);//把当前路径最小的放到vector的末尾 node n = v.back(); v.pop_back(); for (int i = 0; i < v.size(); i++)//结点n加入已求得最短路径的集合后,更新所有结点(加入一个,全部更新一次) { if (dist[n.index][v[i].index] != -1)//n和v[i]都是图中的结点,n到v[i]间有路径 { int now = dist[n.index][v[i].index] + n.curDist; if (now < v[i].curDist) { v[i].curDist = now; v[i].preCity.clear(); v[i].preCity.push_back(n); } else if (now == v[i].curDist)//这一步很关键 v[i].preCity.push_back(n); } } q.push_back(n);//n为图中已求得最短路径的结点 }}void getPath(int index, int curCost, vector<int> &seq)//求得最短路径,相当强悍{ if (q[index].index == s) { if (curCost < totalCost)//求得结果一次,保存一次,如果有cost更小的路径,则更新 { totalCost = curCost; result = seq; } } else { for (int i = 0; i < q[index].preCity.size(); i++)//回溯法求得有多个最短路径时的最短花费 { seq.push_back(q[index].preCity[i].index); curCost += cost[index][q[index].preCity[i].index]; getPath(q[index].preCity[i].index, curCost, seq);//典型的回溯法,上下对称 curCost -= cost[index][q[index].preCity[i].index]; seq.pop_back(); } }}int main(){#ifdef ONLINE_JUDGE#else freopen("D:\\in.txt", "r", stdin); freopen("D:\\out.txt", "w", stdout);#endif cin >> n >> m >> s >> d; int i = 0; dist = vector<vector<int>>(n, vector<int>(n, -1)); cost = vector<vector<int>>(n, vector<int>(n, -1)); int t1, t2, t3, t4; while (i < m) { cin >> t1 >> t2 >> t3 >> t4; dist[t1][t2] = dist[t2][t1] = t3; cost[t1][t2] = cost[t2][t1] = t4; i++; } Dijkstra(); sort(q.begin(), q.end(), cmp1); vector<int> tmp; getPath(d, 0, tmp);//不断地沿着终点找到起点 //不断沿着preCity走到s,这样得到的是按照t到s的顺序,所以要反向输出 for (vector<int>::reverse_iterator rit = result.rbegin(); rit != result.rend(); rit++) cout << *rit << " "; cout << d << " " << q[d].curDist << " " << totalCost << endl;}
代码如下(稍加修改):
#include<iostream>#include<vector>#include<algorithm>#include<fstream>#include<iterator>#include<utility>using namespace std;const int MAXINT = 0x7fffffff;const int MAXV = 501;int totalCost = MAXINT;//总花费struct node{ int index; int curDist;//此结点距起始结点的距离 vector<node> preCity;//路径上当前结点的前一个结点,当有不同的路径,距离相同时,均保存下来 node(int i, int c) :index(i), curDist(c){};};vector<node> v;//图中的所有结点vector<node> p;//保存已求得最短路径的结点vector<vector<int> > dist;//图中两个结点的距离vector<vector<int> > cost;//图中两个结点的花费vector<int> result;//最短路径最短花费序列bool mycmp(const node& a, const node& b){ return a.curDist > b.curDist;}bool mycmp1(const node& a, const node& b){ return a.index < b.index;}int num,m,s,d;//总结点个数void dijkstra(){ for (int i = 0; i < num; i++) { v.push_back(node(i, MAXINT));//初始化 } v[s].curDist = 0; while (!v.empty()) { make_heap(v.begin(), v.end(), mycmp); pop_heap(v.begin(), v.end(),mycmp); node n = v.back(); v.pop_back(); for (int i = 0; i <v.size(); i++)//更新所有结点 { if (dist[n.index][v[i].index] != -1) { int now = dist[n.index][v[i].index] + n.curDist; if (now < v[i].curDist) { v[i].curDist = now; v[i].preCity.clear(); v[i].preCity.push_back(n); } else if (now == v[i].curDist)//重复路径 { v[i].preCity.push_back(n); } } } p.push_back(n);//保存已求得最短径的结点 }}void getPath(node d, int curCost, vector<int>& seq){ if (d.index == s) { if (curCost < totalCost) { totalCost = curCost; result = seq; } } else { for (int i = 0; i < d.preCity.size(); i++) { curCost += cost[d.index][d.preCity[i].index]; seq.push_back(d.preCity[i].index); getPath(d.preCity[i], curCost, seq); curCost -= cost[d.index][d.preCity[i].index]; seq.pop_back(); } }}int main(){#ifdef ONLINE_JUDGE#else freopen("D:\\in.txt", "r", stdin); freopen("D:\\out.txt", "w", stdout);#endif cin >> num >> m >> s >> d; int c1, c2, dis, c; dist = vector<vector<int> >(num, vector<int>(num, -1)); cost = vector<vector<int> >(num, vector<int>(num, -1)); while (m--) { cin >> c1 >> c2 >> dis >> c; dist[c1][c2] = dist[c2][c1] = dis; cost[c1][c2] = cost[c2][c1] = c; } dijkstra(); vector<int> tmp; sort(p.begin(), p.end(), mycmp1);//方便下面求路径时利用 getPath(p[d], 0, tmp); for (vector<int>::reverse_iterator rit = result.rbegin(); rit != result.rend(); rit++) { cout<< (*rit)<<" "; } cout <<d<<" "<< p[d].curDist << " " << totalCost << endl; return 0;}
- PAT 1030 Travel Plan (30)
- pat 1030 Travel Plan
- PAT 1030 Travel Plan SPFA
- 1030. Travel Plan (30)-PAT
- 1030. Travel Plan (30) PAT
- PAT 1030. Travel Plan (30)
- PAT 1030. Travel Plan (30)
- PAT 1030. Travel Plan (30)
- 【PAT】1030. Travel Plan (30)
- pat 1030. Travel Plan (30)
- PAT A1030 Travel Plan(30)
- PAT A1030. Travel Plan (30)
- PAT 1030. Travel Plan (30)
- pat-a1030. Travel Plan (30)
- 1030 Travel Plan (30)
- PAT (Advanced Level) Practise 1030 Travel Plan (30)
- PAT (Advanced Level) Practise 1030 Travel Plan (30)
- 浙大PAT 1030题 1030. Travel Plan
- 为什么说胸大无脑?
- iOS开发26:UIImageView常用操作
- Cocos2d-x2.1.4的android环境配置及使用
- Linux压缩打包命令使用方法
- Java多线程学习——Condition的使用
- PAT 1030 Travel Plan (30)
- Java开发中的23种设计模式详解
- EXT学习之路【发现一个重点】会引起滚动条的异常
- C++笔试题 String类的实现 三大复制控制函数
- iOS appStore中的应用 实现升级功能2
- android开发必备知识
- Task(Activity栈) 详解
- 根文件系统的建立
- Android 如何把状态栏信号格改为5格