一开始看错了题目,以为第一个输出是要求最短距离,后来才发现是要求最短路径的条数。对于最短路径的条数和点权之和我们可以分别用两个数组numberPath[]和numberTeam[]来实现,numberPath[i]记录从起点到顶点i的最短路径的条数,numberTeam[i]记录从从起点到顶点i的所有最短路径中点权之和的最大值。然后当加入新的顶点之后得到的距离等于原来的最短距离,则对numberPath进行累加,此时如果新的最短路径上的点权之和最大,则更新numberTeam。
若加入新的顶点之后距离更小了,则更新最短距离,重置最短路径条数为起点到加入的点之间的最短路径条数,并重新计算新的最短路径上的点权之和。
提交代码:
<span style="font-size:18px;">#include <iostream>
#include <algorithm>
using namespace std;
const int MAXV = 510;
const int INF = 10000000;
int n, m, G[MAXV][MAXV];
int d[MAXV]; //记录起点到各点的最短路径长度
bool vis[MAXV] = {false};
int team[MAXV]; //记录每个城市的team数量,即点权
int currentV, saveV; //起点和终点
int numberPath[MAXV]; //记录起点到各点的最短路径的条数
int numberTeam[MAXV]; //记录起点到各点最短路径上经过的所有点的权值之和
void Dijkstra()
{
d[currentV] = 0; //起点到自身的距离为0
numberTeam[currentV] = team[currentV]; //到起点的总权值之和初始化为起点的点权
for(int i = 0; i < n; i++) //选到起点距离最小的点
{
int u = -1, MIN = INF;
for(int j = 0; j < n; j++)
if(!vis[j] && d[j] < MIN)
MIN = d[u = j];
if(u == -1) return ; //如果所有的点都加入集合了,则返回
vis[u] = true;
for(int v = 0; v < n; v++)
if(!vis[v])
{
if(d[u] + G[u][v] == d[v])
{
numberPath[v] += numberPath[u]; //累加最短路径的条数
if(numberTeam[u] + team[v] > numberTeam[v]) //找到更大的,则更新总的点权
numberTeam[v] = numberTeam[u] + team[v];
}
else if(d[u] + G[u][v] < d[v])
{
numberPath[v] = numberPath[u];
d[v] = d[u] + G[u][v]; //更新最短距离
numberTeam[v] = numberTeam[u] + team[v]; //计算最短路径上的点权之和
}
}
}
}
int main()
{
//freopen("in.txt", "r", stdin);
cin >> n >> m >> currentV >> saveV; //输入城市的个数、路的条数、当前所在地和目的地
for(int i = 0; i < n; i++)
cin >> team[i];
for(int i = 0; i < n; i++) //初始化邻接矩阵G
for(int j = 0; j < n; j++)
G[i][j] = INF;
fill(d, d + MAXV, INF); //初始化距离为无穷大
fill(numberPath, numberPath + MAXV, 1); //初始化 起点到各点的路径条数为1
int start, end, distance;
for(int i = 0; i < m; i++)
{
cin >> start >> end >> distance;
G[start][end] = G[end][start] = distance;
}
Dijkstra();
cout << numberPath[saveV] << " " << numberTeam[saveV];
}
</span>