本题使用 Dijkstra算法,注意几个点:
- 路径长度相同时,按照路径的字典序排序,注意要比较整条路经而不是单个结点;
- 输入起点和终点为同一个点时,不能输出 --> 符号。
(涉及记录路径和路径排序时,Floyd算法更加方便,不过时间复杂度比 Dijkstra算法高)
#include <iostream>
#include <cstring>
using namespace std;
const int MAXN = 100;
const int INF = 0x3f3f3f3f;
int N;
int mp[MAXN][MAXN]; //地图
int tax[MAXN]; //过路费
int vis[MAXN]; //访问情况
int dis[MAXN]; //从起点到其他结点的最短距离
int pre[MAXN]; //最短路径上每个结点的前一个结点
int output[MAXN]; //输出
int st, ed; //起点,终点
int pos;
//深搜,用于比较字典序时,生成完整路径
void dfs(int u, char* s)
{
if (u == st)
return;
dfs(pre[u], s);
s[pos++] = u + '0';
}
//比较两条路径的字典序
bool cmp(int u, int v)
{
char s1[MAXN], s2[MAXN];
pos = 0;
dfs(u, s1);
s1[pos] = '\0';
pos = 0;
dfs(v, s2);
s2[pos] = '\0';
if (strcmp(s1, s2) > 0)
return true;
else
return false;
}
//Dijkstra算法
void Dijkstra(int s, int e)
{
for (int i = 1; i <= N; i++)
{
if (mp[s][i] != -1)
{
dis[i] = mp[s][i];
pre[i] = s;
}
else
dis[i] = INF;
}
vis[s] = 1;
for (int i = 1; i < N; i++)
{
int temp;
int minDis = INF;
for (int j = 1; j <= N; j++)
{
if (!vis[j] && dis[j] < minDis)
{
minDis = dis[j];
temp = j;
}
}
vis[temp] = 1;
for (int j = 1; j <= N; j++)
{
if (mp[temp][j] != -1)
{
if (dis[temp] + mp[temp][j] < dis[j])
{
dis[j] = dis[temp] + mp[temp][j];
pre[j] = temp;
}
else if (dis[temp] + mp[temp][j] == dis[j] && cmp(j, temp))
pre[j] = temp;
}
}
}
}
int main()
{
while (cin >> N)
{
if (N == 0)
break;
for (int i = 1; i <= N; i++) //原始地图
{
for (int j = 1; j <= N; j++)
cin >> mp[i][j];
}
for (int i = 1; i <= N; i++) //过路费
{
cin >> tax[i];
}
for (int i = 1; i <= N; i++) //加入过路费的地图
{
for (int j = 1; j <= N; j++)
{
if (i != j && mp[i][j] != -1)
mp[i][j] += tax[j];
}
}
while (cin >> st >> ed)
{
if (st == -1 && ed == -1)
break;
memset(vis, 0, sizeof(vis));
memset(pre, 0, sizeof(pre));
Dijkstra(st, ed);
cout << "From " << st << " to " << ed << " :" << endl;
int total = 0;
int temp = ed;
while (temp != st) //生成路径
{
output[total++] = temp;
temp = pre[temp];
}
output[total] = st;
cout << "Path: ";
for (int i = total; i > 0; i--) //输出
cout << output[i] << "-->";
cout << output[0] << endl;
if (st != ed) //起点和终点不是同一个点,要减去终点的过路费
cout << "Total cost : " << dis[ed] - tax[ed] << endl << endl;
else
cout << "Total cost : " << dis[ed] << endl << endl;
}
}
return 0;
}
继续加油。