題目概述
給出一張圖,每個節點有權值,每條邊也有邊權(正)。
求:
- 最短路的條數
- 所有最短路徑中,點權和的最大值
解法
題爲單源最短路問題,本文使用了Dijkstra算法(纔不是因爲第一天做PAT,只找到之前NOIP的Dijkstra板子,複製了一下就用了)
最短路徑條數求取
Dijkstra算法的核心在於鬆弛操作。如果要對最短路條數進行計數,只需要在鬆弛操作時加上技術操作即可。
設問題中起點爲s;當前選中邊起點爲u,終點爲v,權值爲val;s點到i點的當前最短路徑長爲dist[i],s點到i點的當前最短路徑有path_cnt[i]條。有如下兩種更新操作:
- 如果當前的dist[u]+val < dist[v]
即“之前到v的路徑不是最短路”。則更新dist[v]爲dist[u]+val,同時更新path_cnt[v]爲path_cnt[u]。“要去v當前只知道從u走過去這一條最短路,所以如果走到u共有path_cnt[u]條路的話,走到v的最短路條數也只有path_cnt[u]條路啦。 - 如果當前的dist[u]+val == dist[v]
即“又找到了和之前最短路徑長度一條最短路”。則更新操作爲給新找到的最短路計數。走到u共有path_cnt[u]條路的話,新增的走到v的最短路條數就有path_cnt[u]條路啦。
所有最短路徑中,點權和的最大值求取
此問題和上一個問題思路一致:在找到“更短的路徑”時,更新team_cnt[e.v] = team_cnt[e.u] + a[e.v],在找到“同樣短的路徑”時,判斷這條路徑是否有更大的點權和,如果是,則更新team_cnt[e.v] = team_cnt[e.u] + a[e.v]
核心代碼
dist[s] = 0;
path_cnt[s] = 1;
team_cnt[s] = a[s];
q.push(HeapNode(s, 0));
while (!q.empty()) {
HeapNode x = q.top(); q.pop();
int u = x.u;
if (done[u]) continue;
done[u] = true;
for (int i = 0; i < g[u].size(); i++)
{
Edge& e = edges[g[u][i]];
if (dist[e.v] == dist[e.u] + e.val)
{
path_cnt[e.v] += path_cnt[e.u];
if (team_cnt[e.u] + a[e.v] > team_cnt[e.v])
{
team_cnt[e.v] = team_cnt[e.u] + a[e.v];
}
}
if (dist[e.v] > dist[e.u] + e.val)
{
dist[e.v] = dist[e.u] + e.val;
q.push(HeapNode(e.v, dist[e.v]));
path_cnt[e.v] = path_cnt[e.u];
team_cnt[e.v] = team_cnt[e.u] + a[e.v];
}
}
}
buglist
- 此題圖爲無向圖,最開始建圖的時候忘記添加雙向邊的代碼,wa的莫名其妙