可以直接Dijkstra,也可以先用Dijkstra求出所有最短路,再用DFS选出最佳的一条。
直接用Dijkstra解决,需要设置额外的数组:
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
int intersectNum, streetNum;
int source, destination;
const int inf = 0x7fffffff;
struct node {
int time, length;
node() {
time = inf;
length = inf;
}
}map[520][520];
bool visited[520] = { false };
int minimumDistance[520];
int minimumTime[520];
int previous[520]; //各结点的前驱结点
int intersection[520] = { 0 };
vector<int> getPath(int cur) {
vector<int> path;
while (cur != -1) {
path.push_back(cur);
cur = previous[cur];
}
return path;
}
int main() {
scanf("%d %d", &intersectNum, &streetNum);
for (int i = 0;i < streetNum;i++) {
int v1, v2, oneway, length, time;
scanf("%d %d %d %d %d", &v1, &v2, &oneway, &length, &time);
map[v1][v2].length = length;
map[v1][v2].time = time;
if (oneway == 0) {
map[v2][v1].length = length;
map[v2][v1].time = time;
}
}
scanf("%d %d", &source, &destination);
//Dijkstra找距离最短路
fill(minimumDistance, minimumDistance + 520, inf);
fill(minimumTime, minimumTime + 520, inf);
fill(visited, visited + 520, false);
fill(previous, previous + 520, -1);
minimumDistance[source] = 0;
minimumTime[source] = 0;
for (int i = 0;i < intersectNum;i++) {
int u = -1, minDis = inf;
for (int j = 0;j < intersectNum;j++) {
if (!visited[j] && minimumDistance[j] < minDis) {
u = j;
minDis = minimumDistance[j];
}
}
if (u == -1)
break;
visited[u] = true;
for (int v = 0;v < intersectNum;v++) {
if (!visited[v] && map[u][v].length != inf) {
if (map[u][v].length + minimumDistance[u] < minimumDistance[v] ||
map[u][v].length + minimumDistance[u] == minimumDistance[v] && map[u][v].time + minimumTime[u] < minimumTime[v]) {
previous[v] = u;
minimumDistance[v] = map[u][v].length + minimumDistance[u];
minimumTime[v] = map[u][v].time + minimumTime[u];
}
}
}
}
vector<int> shortestDisPath = getPath(destination);
int minDistance = minimumDistance[destination];
//Dijkstra找时间最短路
fill(minimumDistance, minimumDistance + 520, inf);
fill(minimumTime, minimumTime + 520, inf);
fill(visited, visited + 520, false);
fill(previous, previous + 520, -1);
fill(intersection, intersection + 520, inf);
minimumTime[source] = 0;
minimumDistance[source] = 0;
intersection[source] = 0;
for (int i = 0;i < intersectNum;i++) {
int u = -1, minT = inf;
for (int j = 0;j < intersectNum;j++) {
if (!visited[j] && minimumTime[j] < minT) {
u = j;
minT = minimumTime[j];
}
}
if (u == -1)
break;
visited[u] = true;
for (int v = 0;v < intersectNum;v++) {
if (!visited[v] && map[u][v].time != inf) {
if (map[u][v].time + minimumTime[u] < minimumTime[v] ||
map[u][v].time + minimumTime[u] == minimumTime[v] && intersection[u] + 1 < intersection[v]) {
previous[v] = u;
minimumTime[v] = map[u][v].time + minimumTime[u];
intersection[v] = intersection[u] + 1;
}
}
}
}
vector<int> shortestTimePath = getPath(destination);
int minTime = minimumTime[destination];
if (shortestTimePath == shortestDisPath) {
printf("Distance = %d; Time = %d: ", minDistance, minTime);
for (int i = shortestTimePath.size() - 1;i >= 0;i--) {
printf("%d", shortestTimePath[i]);
if (i != 0)
printf(" -> ");
}
}
else {
printf("Distance = %d: ", minDistance);
for (int i = shortestDisPath.size() - 1;i >= 0;i--) {
printf("%d", shortestDisPath[i]);
if (i != 0)
printf(" -> ");
}
printf("\n");
printf("Time = %d: ", minTime);
for (int i = shortestTimePath.size() - 1;i >= 0;i--) {
printf("%d", shortestTimePath[i]);
if (i != 0)
printf(" -> ");
}
}
}
先求出所有最短路,再从中找出最佳路径,需要配合dfs求解:
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
int intersectNum, streetNum;
int source, destination;
const int inf = 0x7fffffff;
struct node {
int time, length;
node() {
time = inf;
length = inf;
}
}map[520][520];
bool visited[520] = { false };
int minimumDistance[520];
int minimumTime[520];
vector<int> previous[520]; //各结点的前驱结点
int minTime = inf;
vector<int> shortestDisPath;
void findMinDisPath(int cur, int curTime, vector<int> path) {
if (cur == source) {
if (curTime < minTime) {
shortestDisPath = path;
minTime = curTime;
}
return;
}
for (int i = 0;i < previous[cur].size();i++) {
path.push_back(previous[cur][i]);
findMinDisPath(previous[cur][i], curTime + map[previous[cur][i]][cur].time, path);
path.pop_back();
}
}
int minIntersection = inf;
vector<int> shortestTimePath;
void findMinTimePath(int cur, vector<int> path) {
if (cur == source) {
if (path.size() < minIntersection) {
shortestTimePath = path;
minIntersection = path.size();
}
return;
}
for (int i = 0;i < previous[cur].size();i++) {
path.push_back(previous[cur][i]);
findMinTimePath(previous[cur][i], path);
path.pop_back();
}
}
int main() {
scanf("%d %d", &intersectNum, &streetNum);
for (int i = 0;i < streetNum;i++) {
int v1, v2, oneway, length, time;
scanf("%d %d %d %d %d", &v1, &v2, &oneway, &length, &time);
map[v1][v2].length = length;
map[v1][v2].time = time;
if (oneway == 0) {
map[v2][v1].length = length;
map[v2][v1].time = time;
}
}
scanf("%d %d", &source, &destination);
//Dijkstra找距离最短路
fill(minimumDistance, minimumDistance + 520, inf);
fill(visited, visited + 520, false);
minimumDistance[source] = 0;
for (int i = 0;i < intersectNum;i++) {
int u = -1, minDis = inf;
for (int j = 0;j < intersectNum;j++) {
if (!visited[j] && minimumDistance[j] < minDis) {
u = j;
minDis = minimumDistance[j];
}
}
if (u == -1)
break;
visited[u] = true;
for (int v = 0;v < intersectNum;v++) {
if (!visited[v] && map[u][v].length != inf) {
if (map[u][v].length + minimumDistance[u] < minimumDistance[v]) {
previous[v].clear();
previous[v].push_back(u);
minimumDistance[v] = map[u][v].length + minimumDistance[u];
}
else if (map[u][v].length + minimumDistance[u] == minimumDistance[v]) {
previous[v].push_back(u);
}
}
}
}
vector<int> temp;
temp.push_back(destination);
findMinDisPath(destination, 0, temp);
//Dijkstra找时间最短路
fill(minimumTime, minimumTime + 520, inf);
fill(visited, visited + 520, false);
for (int i = 0;i < 520;i++)
previous[i].clear();
minimumTime[source] = 0;
for (int i = 0;i < intersectNum;i++) {
int u = -1, minT = inf;
for (int j = 0;j < intersectNum;j++) {
if (!visited[j] && minimumTime[j] < minT) {
u = j;
minT = minimumTime[j];
}
}
if (u == -1)
break;
visited[u] = true;
for (int v = 0;v < intersectNum;v++) {
if (!visited[v] && map[u][v].time != inf) {
if (map[u][v].time + minimumTime[u] < minimumTime[v]) {
previous[v].clear();
previous[v].push_back(u);
minimumTime[v] = map[u][v].time + minimumTime[u];
}
if (map[u][v].time + minimumTime[u] == minimumTime[v]) {
previous[v].push_back(u);
}
}
}
}
temp.clear();
temp.push_back(destination);
findMinTimePath(destination, temp);
bool samePath = true;
if (shortestDisPath.size() != shortestTimePath.size()) {
samePath = false;
}
else {
for (int i = 0;i < shortestDisPath.size();i++) {
if (shortestDisPath[i] != shortestTimePath[i])
samePath = false;
break;
}
}
if (shortestTimePath == shortestDisPath) {
printf("Distance = %d; Time = %d: ", minimumDistance[destination], minimumTime[destination]);
for (int i = shortestTimePath.size() - 1;i >= 0;i--) {
printf("%d", shortestTimePath[i]);
if (i != 0)
printf(" -> ");
}
}
else {
printf("Distance = %d: ", minimumDistance[destination]);
for (int i = shortestDisPath.size() - 1;i >= 0;i--) {
printf("%d", shortestDisPath[i]);
if (i != 0)
printf(" -> ");
}
printf("\n");
printf("Time = %d: ", minimumTime[destination]);
for (int i = shortestTimePath.size() - 1;i >= 0;i--) {
printf("%d", shortestTimePath[i]);
if (i != 0)
printf(" -> ");
}
}
}
二刷:
改用cin后比一刷代码的运行时间更长。
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int inf = 0x7fffffff;
int vertexNum, edgeNum, source, dest;
struct node {
int length = inf, time = inf;
}map[500][500];
bool visited[500];
int totalLength[500];
int totalTime[500];
int totalVertex[500];
int shortestPreNode[500];
int fastestPreNode[500];
int main() {
cin >> vertexNum >> edgeNum;
for (int i = 0; i < edgeNum; i++) {
int v1, v2, oneway, len, time;
cin >> v1 >> v2 >> oneway >> len >> time;
map[v1][v2].length = len;
map[v1][v2].time = time;
if (oneway == 0) {
map[v2][v1].length = len;
map[v2][v1].time = time;
}
}
cin >> source >> dest;
fill(visited, visited + 500, false);
fill(totalLength, totalLength + 500, inf);
fill(totalTime, totalTime + 500, inf);
fill(shortestPreNode, shortestPreNode + 500, -1);
totalTime[source] = 0;
totalLength[source] = 0;
for (int i = 0; i < vertexNum; i++) {
int u = -1, minDis = inf;
for (int j = 0; j < vertexNum; j++) {
if (!visited[j] && totalLength[j] < minDis) {
u = j;
minDis = totalLength[j];
}
}
if (u == -1) {
break;
}
visited[u] = true;
for (int v = 0; v < vertexNum; v++) {
if (!visited[v] && map[u][v].length != inf) {
if (totalLength[u] + map[u][v].length < totalLength[v]) {
shortestPreNode[v] = u;
totalTime[v] = totalTime[u] + map[u][v].time;
totalLength[v] = totalLength[u] + map[u][v].length;
}
else if (totalLength[u] + map[u][v].length == totalLength[v]) {
if (totalTime[v] > totalTime[u] + map[u][v].time) {
shortestPreNode[v] = u;
totalTime[v] = totalTime[u] + map[u][v].time;
}
}
}
}
}
vector<int> shortest;
int cur = dest;
while (cur != -1) {
shortest.push_back(cur);
cur = shortestPreNode[cur];
}
fill(fastestPreNode, fastestPreNode + 500, -1);
fill(totalTime, totalTime + 500, inf);
totalTime[source] = 0;
fill(visited, visited + 500, false);
fill(totalVertex, totalVertex + 500, inf);
totalVertex[source] = 1;
for (int i = 0; i < vertexNum; i++) {
int u = -1, minTime = inf;
for (int j = 0; j < vertexNum; j++) {
if (!visited[j] && totalTime[j] < minTime) {
minTime = totalTime[j];
u = j;
}
}
if (u == -1) {
break;
}
visited[u] = true;
for (int v = 0; v < vertexNum; v++) {
if (!visited[v] && map[u][v].time != inf) {
if (totalTime[u] + map[u][v].time < totalTime[v]) {
fastestPreNode[v] = u;
totalVertex[v] = totalVertex[u] + 1;
totalTime[v] = totalTime[u] + map[u][v].time;
}
else if (totalTime[u] + map[u][v].time == totalTime[v]) { //不同路径到达结点v的时间相等
if (totalVertex[v] > totalVertex[u] + 1) { //当前路径经过的结点数更少
totalVertex[v] = totalVertex[u] + 1;
fastestPreNode[v] = u;
}
}
}
}
}
cur = dest;
vector<int> fastest;
while (cur != -1) {
fastest.push_back(cur);
cur = fastestPreNode[cur];
}
if (fastest == shortest) {
printf("Distance = %d; Time = %d: ", totalLength[dest], totalTime[dest]);
for (int i = shortest.size() - 1; i >= 0; i--) {
cout << shortest[i];
if (i != 0) {
cout << " -> ";
}
}
cout << endl;
}
else {
printf("Distance = %d: ", totalLength[dest]);
for (int i = shortest.size() - 1; i >= 0; i--) {
cout << shortest[i];
if (i != 0) {
cout << " -> ";
}
}
cout << endl;
printf("Time = %d: ", totalTime[dest]);
for (int i = fastest.size() - 1; i >= 0; i--) {
cout << fastest[i];
if (i != 0) {
cout << " -> ";
}
}
cout << endl;
}
}