题目大意
给出一个有向图,求有向图上每条边被多少不同的最短路通过。
n ≤ 1500 , e ≤ 5000 n\le1500,e\le5000 n≤1500,e≤5000
解题分析
签到题?反正并不难,就对于每个点先求最短路,然后取出所有 d s t [ x ] + w [ j ] = = d s d [ s o n [ j ] ] dst[x]+w[j]==dsd[son[j]] dst[x]+w[j]==dsd[son[j]]对跑出来的图进行拓扑排序,正着做一遍求出从起点到达点 u u u的最短路方案 s x [ u ] sx[u] sx[u],倒着做一遍求出以点 v v v为起点的最短路方案 s y [ v ] sy[v] sy[v]。一条边在这张图里的贡献就是 s x [ u ] ∗ s y [ v ] sx[u]*sy[v] sx[u]∗sy[v]。
示例代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
const int tt=1000000007,maxn=1505,maxe=5005;
int n,e,tot,ans[maxe],son[maxe],w[maxe],nxt[maxe],lnk[maxn];
int dst[maxn],que[maxn],qu[maxn],in[maxn],sx[maxn],sy[maxn];
bool vs[maxn],vis[maxe];
void _add(int x,int y,int z){son[++tot]=y; w[tot]=z; nxt[tot]=lnk[x]; lnk[x]=tot;}
void _tuopu(int s){
memset(vis,0,sizeof(vis));
for (int i=1;i<=n;i++)
for (int j=lnk[i];j;j=nxt[j]) in[son[j]]+=(vis[j]=(dst[i]+w[j]==dst[son[j]]));
for (int i=1;i<=n;i++) {sx[i]=0; sy[i]=1;}
int hed=0,til=1; qu[1]=s; sx[s]=1;
while (hed<til)
for (int j=lnk[qu[++hed]];j;j=nxt[j])
if (vis[j]&&!(--in[son[j]])) qu[++til]=son[j];
for (int i=1;i<=til;i++)
for (int j=lnk[qu[i]];j;j=nxt[j])
if (vis[j]) sx[son[j]]+=sx[qu[i]];
for (int i=til;i;i--)
for (int j=lnk[qu[i]];j;j=nxt[j])
if (vis[j]) sy[qu[i]]+=sy[son[j]];
for (int i=1;i<=n;i++)
for (int j=lnk[i];j;j=nxt[j])
if (vis[j]) ans[j]=(ans[j]+(LL)sx[i]*sy[son[j]]%tt)%tt;
}
void _spfa(int s){
memset(vs,0,sizeof(vs));
memset(in,0,sizeof(in));
memset(dst,63,sizeof(dst));
int hed=0,til=1; que[1]=s; dst[s]=0; vs[s]=1;
while (hed!=til){
hed=(hed+1)%maxn; vs[que[hed]]=0;
for (int j=lnk[que[hed]];j;j=nxt[j])
if (dst[son[j]]>dst[que[hed]]+w[j]){
dst[son[j]]=dst[que[hed]]+w[j];
if (!vs[son[j]]){
til=(til+1)%maxn; que[til]=son[j]; vs[son[j]]=1;
if (dst[son[j]]>dst[(hed+1)%maxn]) swap(que[til],que[(hed+1)%maxn]);
}
}
}
_tuopu(s);
}
int main()
{
freopen("road.in","r",stdin);
freopen("road.out","w",stdout);
scanf("%d%d",&n,&e); tot=0;
for (int i=1,x,y,z;i<=e;i++){scanf("%d%d%d",&x,&y,&z); _add(x,y,z);}
for (int i=1;i<=n;i++) _spfa(i);
for (int i=1;i<=e;i++) printf("%d\n",ans[i]);
return 0;
}