[PAT解题报告] Travel Plan
给定一个无向图,每条边有一个长度,还有一个费用,要求从起点到终点,先总路程长度最小,如果最短路长度相同,再让费用最小——保证这时答案是唯一的。
分析: 还是dijkstra算法,这个算法之前考过很多次了。例如1013,
1018。我们有两个指标优化,首先是距离,更新距离的时候顺便可以更新费用。只有确定更新距离的时候,再考虑费用,距离相同的话,费用取最小的。
还有注意多重边的处理(题目可能没有多重边), 取距离(长度)最短的,如果长度相同,取费用最小的。
dijkstra算法可以在更新时记录很多东西,总结一下包括:
(1) 最短路的长度——这个显然
(2) 长度相同的时候,可以让第二关键词达到最优(最大或者最小),本题第二关键词是费用
(3) 具体的最短路径, 我们只需要在更新距离的时候,记录pre[x] =
y表示到当前节点x的上一个节点是y,最后从终点递归倒回起点就能求出具体路径。另外如果不喜欢递归,可以从终点倒过来算最短路,就算到起点,然后从终点沿着pre的信息(或许叫next更好些)一步一步正着走下去,也可以求出最短路径来。
代码:
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
const int inf = 1000000000;
const int N = 502;
int n;
bool mark[N];
int a[N][N];
int b[N][N];
int dis[N];
int cost[N];
int pre[N];
void print(int now,int from) {
if (now != from) {
print(pre[now], from);
}
printf("%d ",now);
}
void dijkstra(int from) {
for (int i = 0; i < n; ++i) {
cost[i] = dis[i] = inf;
mark[i] = false;
}
cost[from] = dis[from] = 0;
for (int j = 0; j < n; ++j) {
int k = -1;
for (int i = 0; i < n; ++i) {
if ((!mark[i]) && ((k < 0) || (dis[i] < dis[k]))) {
k = i;
}
}
mark[k] = true;
for (int i = 0; i < n; ++i) {
if ((!mark[i]) && (a[k][i] < inf)) {
int maydis = dis[k] + a[k][i];
int maycost = cost[k] + b[k][i];
if ((maydis < dis[i]) || ((maydis == dis[i]) && (maycost < cost[i]))) {
pre[i] = k;
dis[i] = maydis;
cost[i] = maycost;
}
}
}
}
}
int main() {
int m, from, to;
scanf("%d%d%d%d",&n,&m,&from,&to);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
a[i][j] = b[i][j] = inf;
}
}
for (;m;--m) {
int x,y,d,c;
scanf("%d%d%d%d",&x,&y,&d,&c);
if ((a[x][y] > d) || ((a[x][y] == d) && (b[x][y] > c))) {
a[x][y] = a[y][x] = d;
b[x][y] = b[y][x] = c;
}
}
dijkstra(from);
print(to,from);
printf("%d %d\n",dis[to],cost[to]);
return 0;
}
原题链接: http://www.patest.cn/contests/pat-a-practise/1030


SHEIN希音公司福利 318人发布