其他分享
首页 > 其他分享> > cf1650 G. Counting Shortcuts

cf1650 G. Counting Shortcuts

作者:互联网

题意:

给定边权为1的无向图,给定起点 S 和终点 E。设 S 到 E 的最短路长度为 d,求 S 到 E 的长不大于 d+1 的路径数量

思路:

看看长为最短路+1的路有啥性质。首先容易证明它一定是简单路。进一步还可以知道,如果以S为源点对图做bfs分层,最多只有一条边的两端点在同一层,其它边都是从 \(dep\) 层指向 \(dep+1\) 层

先做普通的 bfs 最短路计数,求出 S 到每个点的最短路长度 dS 和数量 cntS,以及 E 到每个点的最短路长度 dE 和数量 cntE,那么

\[ans=\sum_{u与v相邻且在同一层,dS_u+dE_v=dS_E} cntS_u \cdot cntE_v \]

遍历所有边算出上述 ans

const signed N = 3 + 2e5, mod = 1e9 + 7;
int n, m, S, E; vector<int> G[N];

void bfs(int S, vector<int> &d, vector<int> &cnt) { //bfs最短路计数
    queue<int> q; q.push(S);
    vector<bool> vis(n+1,0);
    d[S] = 0; cnt[S] = 1;
    while(q.size()) {
        int u = q.front(); q.pop();
        for(int v : G[u]) {
            if(!vis[v] && d[v] > d[u] + 1) d[v] = d[u] + 1, q.push(v), vis[v] = 1;
            if(d[v] == d[u] + 1) (cnt[v] += cnt[u]) %= mod;
        }
    }
}

void sol() {
    cin >> n >> m >> S >> E;
    for(int i = 1; i <= n; i++) G[i].clear();
    vector<PII> edges;
    while(m--) {
        int x, y; cin >> x >> y;
        G[x].pb(y), G[y].pb(x);
        edges.pb({x,y}), edges.pb({y,x});
    }

    vector<int> dS(n+1,INF), cntS(n+1,0);
    bfs(S, dS, cntS);
    vector<int> dE(n+1,INF), cntE(n+1,0);
    bfs(E, dE, cntE);

    ll ans = cntS[E]; //长为最短路的
    for(auto &[u,v]: edges) //长为最短路+1的
        if(dS[u] == dS[v] && dS[u] + dE[v] == dS[E]) 
            (ans += (ll)cntS[u] * cntE[v]) %= mod;
    cout << ans << endl;
}

标签:Shortcuts,短路,cf1650,bfs,int,vector,cntS,Counting,dS
来源: https://www.cnblogs.com/wushansinger/p/16281997.html