BZOJ 2750: [HAOI2012]Road(最短路+拓扑排序+递推)
2018-03-23 14:06
281 查看
题目描述
传送门题目大意:给你一个n个点、m条边的
4000
有向图,问你每条边被多少条不同的最短路经过,答案对10^9+7取模,其中n<=1500,m<=5000。
题解
由于n、m都不大,一个显然的做法是枚举一个起点S,然后跑SPFA。对于一条边,如果它不在最短路图上,就肯定不会被算上。而一条边i->j在图上的充要条件是Dis[i]+l<=Dis[j],构出来这个图你就会发现这是个DAG。然后DAG上所有边都是从S出发到某个点的最短路上的边。换而言之,从S出发沿一条路径访问到的每一个点,该点的最短路就是该路径的长度。所以很容易想到对于一条边u->v的答案贡献就是f[u]*g[v]。
其中f[u]代表沿S到u的路径方案数,g[v]代表v能到达的所有点的路径方案数(注意不是点的个数)。这里自行体会一下就能明白。
现在我们只需对DAG进行拓扑排序,然后正向递推出f,对于g,反着建一遍最短路图,然后同样也能算出来。
最后每条原边的答案就是∑f[u]*g[v]了。代码比较好写,但要建三个图,细节处理要注意(我一开始忘了第二次建的图是反过来的,导致答案算反了QAQ)。
代码
#include <bits/stdc++.h> #define maxn 1555 #define maxm 5005 #define INF 0x7FFFFFFF #define MOD 1000000007 using namespace std; typedef long long LL; int n, m; int cur[2]; struct List{ int obj, len, id; List *next; }*head[2][maxn], Edg[2][maxm]; void Addedge(int p, int a, int b, int c, int id){ Edg[p][++cur[p]].next = head[p][a]; Edg[p][cur[p]].obj = b; Edg[p][cur[p]].len = c; Edg[p][cur[p]].id = id; head[p][a] = Edg[p]+cur[p]; } LL ans[maxm]; bool Vis[maxn]; int q[maxn]; int f[maxn], g[maxn], Dis[maxn], in[maxn]; void SPFA(int S){ int hh, tt; q[hh = tt = 0] = S; for(int i = 1; i <= n; i++) Dis[i] = INF, Vis[i] = false; Dis[S] = 0; Vis[S] = true; while(hh <= tt){ int now = q[hh%n]; hh ++; for(List *p = head[0][now]; p; p = p->next){ int v = p->obj, l = p->len; if(Dis[now] + l < Dis[v]){ Dis[v] = Dis[now] + l; if(!Vis[v]){ Vis[v] = true; tt ++; q[tt%n] = v; if(Dis[q[hh%n]] > Dis[q[tt%n]]) swap(q[hh%n], q[tt%n]); } } } Vis[now] = false; } } void Topo(int P, int *x){ cur[1] = -1; for(int i = 1; i <= n; i++) head[1][i] = NULL, in[i] = 0, x[i] = P; for(int i = 1; i <= n; i++){ if(Dis[i] == INF) continue; for(List *p = head[0][i]; p; p = p->next){ int v = p->obj, l = p->len, id = p->id; if(Dis[i] + l <= Dis[v]){ if(!P){ Addedge(1, i, v, l, id); in[v] ++; } else{ Addedge(1, v, i, l, id); in[i] ++; } } } } int hh = 0, tt = -1; for(int i = 1; i <= n; i++) if(Dis[i] != INF && !in[i]) q[++tt] = i, x[i] = 1; while(hh <= tt){ int now = q[hh++]; for(List *p = head[1][now]; p; p = p->next){ int v = p->obj; x[v] += x[now]; in[v] --; if(!in[v]) q[++tt] = v; } } } int main(){ scanf("%d%d", &n, &m); int a, b, c; cur[0] = -1; for(int i = 1; i <= n; i++) head[0][i] = NULL; for(int i = 1; i <= m; i++){ scanf("%d%d%d", &a, &b, &c); Addedge(0, a, b, c, i); } for(int i = 1; i <= n; i++){ SPFA(i); Topo(0, f); Topo(1, g); for(int j = 1; j <= n; j++) for(List *p = head[1][j]; p; p = p->next){ int v = p->obj, id = p->id; ans[id] = (ans[id] + 1LL * f[v] * g[j]) % MOD; } } for(int i = 1; i <= m; i++) printf("%lld\n", ans[i]); return 0; }
相关文章推荐
- BZOJ2750[HAOI2012]Road 最短路
- 【bzoj2750】【HAOI2012】【Road】【最短路+dp】
- BZOJ 2750: [HAOI2012]Road( 最短路 )
- BZOJ2750 [HAOI2012]Road(最短路)
- BZOJ 2750: [HAOI2012]Road
- BZOJ2750: [HAOI2012]Road
- bzoj 2750: [HAOI2012]Road 最短路+dp
- 【bzoj 2750】: [HAOI2012]Road
- 【BZOJ】【2750】【HAOI2012】Road
- [BZOJ2750][HAOI2012]Road(SPFA+拓扑排序)
- [bzoj2750][HAOI2012]Road
- bzoj 2750: [HAOI2012]Road【spfa+dfs】
- bzoj 2750: [HAOI2012]Road
- bzoj 2752: [HAOI2012]高速公路(road) 线段树
- bzoj 2752: [HAOI2012]高速公路(road)
- BZOJ2752 [HAOI2012]高速公路(road)
- BZOJ 2752 [HAOI2012]高速公路(road)【线段树
- ●BZOJ 2752 [HAOI2012]高速公路(road)
- 2750: [HAOI2012]Road
- bzoj2750 Road 最短路&记忆化搜索