NC19987 [HAOI2012]ROAD
题目
题目描述
C国有n座城市,城市之间通过m条单向道路连接。一条路径被称为最短路,当且仅当不存在从它的起点到终点的另外一条路径总长度比它小。两条最短路不同,当且仅当它们包含的道路序列不同。我们需要对每条道路的重要性进行评估,评估方式为计算有多少条不同的最短路经过该道路。现在,这个任务交给了你。
输入描述
第一行包含两个正整数n、m
接下来m行每行包含三个正整数u、v、w,表示有一条从u到v长度为w的道路
输出描述
输出应有m行,第i行包含一个数,代表经过第i条道路的最短路的数目对1000000007取模后的结果
示例1
输入
4 4 1 2 5 2 3 5 3 4 5 1 4 8
输出
2 3 2 1
备注
30% 的数据满足: 。
60% 的数据满足: 。
100% 的数据满足: 。
题解
知识点:最短路,计数dp,DAG上dp。
为了求出每条边被最短路经过的次数,我们先以每个点出发考虑。
对于某点 为源点,经过一条边 的最短路条数,可以分解为求 为终点的最短路条数,以及 为起点的最短路条数,最后乘在一起就是以 为源点经过这条边的最短路条数。以下是具体步骤:
- 先求出以 为终点的最短路条数,可以通过跑最短路时求出。对于一条边 ,若 ,则 ;若 ,则 。
- 随后求出以 为起点的最短路条数,可以从 自底向上dfs求出,。因为最短路图一定是DAG,所以可以进行DAG上dp。对于某点 的下一个节点 ,如果边 在最短路上,则先求出以 为起点(包括自己为终点,所以初始化 )最短路条数 ,随后可以求出 ,即以 为起点最短路条数。如果某点以及被计算过了,那就跳过。
- 在第二步的同时,我们得到了边 的 和 。那么,这条边以 为源点的答案贡献是 。
对每个点都求一遍,累加每条边的贡献即可。
时间复杂度
空间复杂度
代码
#include <bits/stdc++.h> using namespace std; const int mod = 1e9 + 7; const int N = 1507, M = 5007; struct edge { int v, nxt, w; }e[M]; int h[N], idx; void add(int u, int v, int w) { e[++idx] = { v,h[u],w }; h[u] = idx; } bool vis[N]; int dis[N]; int dp[N];///起点到i点的最短路总数 struct node { int v, w; friend bool operator<(const node &a, const node &b) { return a.w > b.w; } }; priority_queue<node> pq; void dijkstra(int s) { dis[s] = 0; dp[s] = 1; pq.push({ s,0 }); while (!pq.empty()) { int u = pq.top().v; pq.pop(); if (vis[u]) continue; vis[u] = 1; for (int i = h[u];i;i = e[i].nxt) { int v = e[i].v, w = e[i].w; if (dis[v] > dis[u] + w) { dis[v] = dis[u] + w; dp[v] = dp[u]; pq.push(node{ v,dis[v] }); } else if (dis[v] == dis[u] + w) { dp[v] = (dp[u] + dp[v]) % mod; } } } } int dpv[N];///i点把其他点作为终点的最短路总数 int ans[M]; void dfs(int u) { if (dpv[u]) return; dpv[u] = 1;///自己作为终点的一种 for (int i = h[u];i;i = e[i].nxt) { int v = e[i].v, w = e[i].w; if (dis[v] == dis[u] + w) { dfs(v); dpv[u] = (dpv[u] + dpv[v]) % mod; ans[i] = (ans[i] + 1LL * dp[u] * dpv[v]) % mod; } } } int main() { std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int n, m; cin >> n >> m; for (int i = 1;i <= m;i++) { int u, v, w; cin >> u >> v >> w; add(u, v, w); } for (int i = 1;i <= n;i++) { for (int j = 1;j <= n;j++) vis[j] = dp[j] = dpv[j] = 0, dis[j] = 0x3f3f3f3f; dijkstra(i); dfs(i); } for (int i = 1;i <= m;i++) cout << ans[i] << '\n'; return 0; }
本文来自博客园,作者:空白菌,转载请注明原文链接:https://www.cnblogs.com/BlankYang/p/17028821.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧