Codeforces Round #766 (Div. 3) G

G. Counting Shortcuts

题目大意: 给定一个由 n 个点和 m 条边组成的无向图(所有边权为1),并给定起点和终点,求与最短路径差不超过1的路径条数。

思路: 因为所有边权为1,所以答案为起点到终点的最短路径数量和次短路径数量之和。

具体做法: BFS求得起点到所有点的最短路并计数,因为所有边权为1,所以起点到某个点的次短路有两种情况:

  1. 与该点相邻并且最短路径与到该点的最短路径相等的点;
  2. 在起点到该点的最短路径上的点(要求走的是次短路)。

d i s [ i ] dis[i] dis[i] 为起点到 i 点的最短路径, c n t 1 [ i ] cnt1[i] cnt1[i] 为最短路径数量, c n t 2 [ i ] cnt2[i] cnt2[i] 为次短路经数量,则:

if(dis[i] == dis[j]) {
	cnt2[i] += cnt1[j];
}
if(dis[i] == dis[j] + 1) {
	cnt2[i] += cnt2[j];
}

此外,需要特别强调的是,第二种情况需要按最短路径从小到大进行转移。

代码:

constexpr int P = 1e9 + 7;
void solve() {
    int n, m, s, t;
    cin >> n >> m >> s >> t;
    
    vector<vector<int>> adj(n + 1);
    for(int i = 0; i < m; ++i) {
        int u, v;
        cin >> u >> v;
        adj[u].push_back(v);
        adj[v].push_back(u);
    }    

    vector<ll> dis(n + 1, -1), cnt1(n + 1), cnt2(n + 1);
    vector<bool> vis(n + 1);
    queue<int> q;
    q.push(s);
    dis[s] = 0;
    cnt1[s] = 1;
    while(!q.empty()) {
        int u = q.front();
        q.pop();
        for(auto v : adj[u]) {
            if(dis[v] == -1) {
                dis[v] = dis[u] + 1;
                q.push(v);
            }
            if(dis[v] == dis[u] + 1) {
                cnt1[v] = (cnt1[v] + cnt1[u]) % P;
            }
        }
    }

    for(int i = 1; i <= n; ++i) {
        for(auto j : adj[i]) {
            if(dis[j] == dis[i]) {
                cnt2[i] = (cnt2[i] + cnt1[j]) % P;
            }
        }
    }

    vector<pair<int, int>> b(n + 1);
    for(int i = 1; i <= n; ++i) {
        b[i] = make_pair(dis[i], i);
    }
    sort(b.begin(), b.end());

    for(int i = 1; i <= n; ++i) {
        int u = b[i].second;
        for(auto v : adj[u]) {
            if(dis[u] == dis[v] + 1) {
                cnt2[u] = (cnt2[u] + cnt2[v]) % P;
            }
        }
    }

    cout << (cnt1[t] + cnt2[t]) % P << "\n";
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值