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