ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

1044 [HAOI2012]ROAD dijkstra递推求最短路径数+生成反向最短路拓扑图 计算以每个点为顶点,每条边上的最短路条数

2022-08-22 00:03:32  阅读:150  来源: 互联网

标签:ver 拓扑图 1044 int 短路 个数 cnt1 dist


 链接: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
来源: https://www.cnblogs.com/er007/p/16611435.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有