链接:https://ac.nowcoder.com/acm/contest/26077/1044
来源:牛客网
题目描述
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% 的数据满足:n≤15,m≤30n\leq 15, m\leq 30n≤15,m≤30。
60% 的数据满足:n≤300,m≤1000n\leq 300, m\leq 1000n≤300,m≤1000。
100% 的数据满足:n≤1500,m≤5000,w≤10000n\leq 1500, m\leq 5000, w\leq 10000n≤1500,m≤5000,w≤10000。
分析
https://blog.nowcoder.net/n/0ff8d480c1014a57821139788a23ed13?f=comment
题意:求在有向图上,以任意点为起点和终点,以每条边为相关边的最短路个数。
以任意点为起点和终点,
对于边<u,v> ,如果这条边是从 s 到 t 的最短路上的一条边,它作为相关边的最短路个数,根据乘法原理,就是s 到 t 的路径上,从s 到 u 的最短路个数 * v 到 t 的最短路个数。
从s 到 u 的最短路个数:
可以通过dijstra + dp 记录路径数来递推求得:(迪杰斯塔拉本质上也是一个拓扑序,当更新到后一个节点的时候,前面的节点不会再被更新,满足后无效性)
1.设起始点 的 路径数是1 cnt[s] = 1;
2.当dist[j] > dist[u] + w[i] 。此时 j 点的最短路个数 就是 u 点的最短路个数。 cnt[j] = cnt[u]
3.当dist[j] = dist[u] + w[i] 。此时 j 点的最短路个数 是 对 u 点的最短路个数的累加。 cnt[j] += cnt[u]
从 v 到 t 的最短路个数:
由于后无效性,没办法直接计算出 s 到 t 的 中间点 v 到 t 的最短路个数,但如果从 t 为起点建一个反向图,就可以知道了。
直接在dijkstra 跑最短路的时候 建一个拓扑图,只有最短路上的边才会被记录到这个图里,
1. 如果 dist[j] > dist[u] + w[i] 。 先把之前更新过的边删掉:h1[j] = -1;然后再建一条反向边:add1(j , u )
2.如果 dist[j] == dist[u] + w[i]。说明这条边是最短路的边,直接建反向边:add1(j,u)
然后跑拓扑序,递推 cnt[j] += cnt[t] 就可以得到 到达 j 点的最短路个数。 cnt1[u] * cnt2[v] 就是 <u,v> 在这个 拓扑图里的贡献。
为什么要跑每个点?
因为起点不一样最短路也不一样,要计算的是 以每个点为起点每个点为终点的最短路。
//-------------------------代码---------------------------- #define int ll const int N = 1e4+10,mod = 1e9+7; int n,m; int e[N],ne[N],w[N],h[N],idx,id[N]; void add(int a,int b,int c,int d) {e[idx] = b,ne[idx] = h[a],w[idx] = c,id[idx] = d,h[a] = idx ++ ;} int e1[N],ne1[N],w1[N],h1[N],idx1,id1[N]; void add1(int a,int b,int d) {e1[idx1] = b,ne1[idx1] = h1[a],id1[idx1] = d,h1[a] = idx1 ++ ;} bool vis[N]; int d[N],dist[N]; ll cnt1[N],cnt2[N],ans[N]; void init() { idx1 = 0; ms(h1,-1); ms(cnt1,0); ms(vis,0); ms(dist,0x3f); } void dijkstra(int s) { priority_queue<pii,V<pii>,greater<pii>>q; dist[s] = 0;q.push({0,s});cnt1[s] = 1; while(q.size()) { auto tmp = q.top();q.pop();int ver = tmp.y; if(vis[ver]) continue;vis[ver] = 1; for(int i = h[ver];~i;i = ne[i]) { int j = e[i]; if(dist[j] == dist[ver] + w[i]) { add1(j,ver,id[i]);cnt1[j] = (cnt1[j] + cnt1[ver]) % mod; } else if(dist[j] > dist[ver] + w[i] ) { h1[j] = -1;add1(j,ver,id[i]);dist[j] = dist[ver] + w[i]; cnt1[j] = cnt1[ver];q.push({dist[j],j}); } } } } void topsort() { queue<int> q; fo(i,1,n) { for(int j = h1[i];~j;j=ne1[j]) { int son = e1[j]; d[son] ++; } } fo(i,1,n) { if(!d[i]) q.push(i); cnt2[i] = 1; } while(q.size()) { auto t = q.front();q.pop(); for(int i = h1[t];~i;i=ne1[i]) { int j = e1[i]; cnt2[j] = (cnt2[j] + cnt2[t]) % mod; ans[id1[i]] = (ans[id1[i]] + cnt1[j] * cnt2[t] % mod) % mod; if(-- d[j] == 0) q.push(j); } } } void solve() { cin>>n>>m; ms(h,-1); fo(i,1,m) { int u,v,w;cin>>u>>v>>w; add(u,v,w,i); } fo(i,1,n) { init(); dijkstra(i); topsort(); } fo(i,1,m) cout<<ans[i]<<endl; } void main_init() {} signed main(){ AC();clapping();TLE; cout<<fixed<<setprecision(12); main_init(); // while(cin>>n,n) // while(cin>>n>>m,n,m) // int t;cin>>t;while(t -- ) solve(); // {solve(); } return 0; } /*样例区 */ //------------------------------------------------------------
标签:ver,拓扑图,1044,int,短路,个数,cnt1,dist From: https://www.cnblogs.com/er007/p/16611435.html