在解决有多种标尺的最短路径问题中,即当具有相同的最短路径要让总的花费最小等,有两种解决问题的模板代码,一种是直接用Dijkstra算法:只需要增加一个数组来存放新增的边权或点权或最短路径条数,然后在算法中修改优化d[v]的那个步骤即可,其他部分不需要改动;一种是使用Dijkstra+dfs:先在Dijkstra算法中记录所有的最短路径(只考虑距离),然后从这些最短路径中选出一条第二标尺最优的路径。
相关问题链接:travel plan
直接贴代码:
Dijkstra算法:
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXV = 501;
const int INF = 1000000000;
int n, m, s, D;
int g[MAXV][MAXV];
bool vis[MAXV] = {false};
int d[MAXV];
int cost[MAXV][MAXV] = {INF};
int c[MAXV];
int pre[MAXV];
void Dijkstra(int s)
{
fill(d, d+MAXV, INF);
d[s] = 0;
fill(c, c+MAXV, INF);
c[s] = 0;
for(int i = 0; i < n; i++)
pre[i] = i;
for(int i = 0; i < n; i++){
int u = -1, MIN = INF;
for(int j = 0; j < n; j++){
if(vis[j] == false && d[j] < MIN){
u = j;
MIN = d[j];
}
}
if(u == -1) return;
vis[u] = true;
for(int v = 0; v < n; v++){
if(vis[v] == false && g[u][v] != INF){
if(g[u][v] + d[u] < d[v]){
d[v] = g[u][v] + d[u];
c[v] = c[u] + cost[u][v];
pre[v] = u;
}
else if(g[u][v] + d[u] == d[v]){
if(c[v] > c[u] + cost[u][v]){
c[v] = c[u] + cost[u][v];
pre[v] = u;
}
}
}
}
}
}
void dfs(int s, int v)
{
if(s == v){
printf("%d ", s);
return;
}
dfs(s, pre[v]);
printf("%d ", v);
}
int main()
{
scanf("%d%d%d%d", &n,&m,&s,&D);
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
g[i][j] = INF;
for(int i = 0; i < m; i++){
int pa1,pa2,dist,co;
scanf("%d%d%d%d",&pa1,&pa2,&dist,&co);
g[pa1][pa2] = dist;
g[pa2][pa1] = dist;
cost[pa1][pa2] = co;
cost[pa2][pa1] = co;
}
Dijkstra(s);
dfs(s, D);
printf("%d %d\n", d[D], c[D]);
return 0;
}
Dijkstra算法+深搜:
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
const int MAXV = 501;
const int INF = 1000000000;
int n, m, s, D;
int g[MAXV][MAXV];
bool vis[MAXV] = {false};
int d[MAXV];
int cost[MAXV][MAXV] = {INF};
int optValue = INF;
vector<int> pre[MAXV];
vector<int> tmpPath, path;
void Dijkstra(int s)
{
fill(d, d+MAXV, INF);
d[s] = 0;
for(int i = 0; i < n; i++){
int u = -1, MIN = INF;
for(int j = 0; j < n; j++){
if(vis[j] == false && d[j] < MIN){
MIN = d[j];
u = j;
}
}
if(u == -1) return;
vis[u] = true;
for(int v = 0; v < n; v++){
if(vis[v] == false && g[u][v] != INF){
if(d[u]+g[u][v] < d[v]){
d[v] = d[u] + g[u][v];
pre[v].clear();
pre[v].push_back(u);
}
else if(d[u]+g[u][v]==d[v]){
pre[v].push_back(u);
}
}
}
}
}
void dfs(int v){
if(v == s){
tmpPath.push_back(s);
int value = 0;
//calculate the cost
for(int i = tmpPath.size()-1; i > 0; i--){
int id = tmpPath[i], nextId = tmpPath[i-1];
value += cost[id][nextId];
}
if(value < optValue){
optValue = value;
path = tmpPath;
}
tmpPath.pop_back();
return;
}
tmpPath.push_back(v);
for(int i = 0; i < (int)pre[v].size(); i++){
dfs(pre[v][i]);
}
tmpPath.pop_back();
}
int main()
{
scanf("%d%d%d%d", &n,&m,&s,&D);
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
g[i][j] = INF;
for(int i = 0; i < m; i++){
int pa1,pa2,dist,co;
scanf("%d%d%d%d",&pa1,&pa2,&dist,&co);
g[pa1][pa2] = dist;
g[pa2][pa1] = dist;
cost[pa1][pa2] = co;
cost[pa2][pa1] = co;
}
Dijkstra(s);
dfs(D);
for(int i = path.size()-1; i >= 0; i--){
printf("%d ", path[i]);
}
printf("%d %d\n", d[D], optValue);
return 0;
}