分析
对于图中每两个可形成一条路径的点之间,都会有它们的最短路,题目所求的就是对于给出的 \(m\) 条道路,有多少最短路经过该道路。
可以知道这不是一次搜索就可以做到的,因为它会在搜索过程中不断更改最短路,于是我们考虑在确定起点的情况下,它到各点的最短路经过了哪些路径。
我们以 \(f_i\) 表示从起点到该点的最短路长度,于是可以知道,对于每一条路径,如果起点的 \(f\) 值加上道路长度等于终点的 \(f\) 值,那么就说明至少有一条最短路经过了该边,那么有多少条呢?我们用两个数组来解决这个问题。
首先,在找出所有满足条件的路径之后,我们用 \(cntq\) 来表示这些路组成的图中以该点为起点的路有多少,用 \(cntm\) 来表示以该点为终点的,因此对于每一条满足条件的路径,终点需加上起点的 \(cntm\),起点需加上终点的 \(nctq\)。为了保证累加的正确性,我们再采用拓扑排序,正向计算 \(cntm\),反向计算 \(cntq\)。最后对于每一条路径,加上的次数自然就是起点的 \(cntm\) 乘上终点的 \(cntq\) 了,这样此题就解决了。
另外,本题用 \(dijkstra\) 有一个点会超时,\(spfa\) 是可行的,但两个都挂上了,仅供参考。
#include<bits/stdc++.h>
using namespace std;
int n,m,head[1501],vis[1501],flag[5001],f[1501],cnt,ans[5001],sum[1501],cntm[1501],cntq[1501];
const int mod=1e9+7;
struct node{
int to,w,fr,next;
}a[5001];
void read(int &res){
char c;
res=0;
c=getchar();
while(c<‘0‘||c>‘9‘){c=getchar();}
while(c>=‘0‘&&c<=‘9‘)res=(res<<1)+(res<<3)+c-48,c=getchar();
}
priority_queue<pair<int,int> > q;
/*
inline void dijkstra(int qq){
memset(vis,0,sizeof(vis));
memset(flag,0,sizeof(flag));
memset(f,127,sizeof(f));//有一个想法是memset太多了,也不确定
f[qq]=0;
q.push(make_pair(0,qq));
while(q.size()){
int x=q.top().second;q.pop();
if(vis[x])continue;
vis[x]=1;
for(register int i=head[x];i;i=a[i].next){
int v=a[i].to;
if(f[v]>f[x]+a[i].w){
f[v]=f[x]+a[i].w;
q.push(make_pair(-f[v],a[i].to));
}
}
}
for(register int i=1;i<=m;++i){
if(f[a[i].fr]+a[i].w==f[a[i].to])flag[i]=1;
}
}
*/
int que[10001],len;
inline void spfa(int qq) {
memset(f,127,sizeof(f));
memset(flag,0,sizeof(flag));
f[que[len=1]=qq]=0;
for (register int i = 1; i <= len; i++) {
int x=que[i];vis[x]=0;
for (register int i=head[x];i;i=a[i].next){
int v=a[i].to;
if(f[x]+a[i].w<f[v]){
f[v]=f[x]+a[i].w;
if(!vis[v])vis[que[++len]=v]=1;
}
}
}
for(register int i=1;i<=m;++i){
if(f[a[i].fr]+a[i].w==f[a[i].to])flag[i]=1;//满足条件,进行标记
}
}
int qu[1501],tot;
inline void topu(int qq){
memset(sum,0,sizeof(sum));
memset(cntm,0,sizeof(cntm));
memset(cntq,0,sizeof(cntq));
for(register int i=1;i<=m;++i)if(flag[i])sum[a[i].to]++;
cntm[qq]=1;
qu[tot=1]=qq;
for(register int i=1;i<=tot;++i){
int x=qu[i];
for(register int i=head[x];i;i=a[i].next){
if(!flag[i])continue;
int v=a[i].to;
if(!--sum[v])qu[++tot]=v;
cntm[v]=(cntm[v]+cntm[x])%mod;
}
}
for(register int i=tot;i;i--){
int x=qu[i];cntq[x]++;
for(register int i=head[x];i;i=a[i].next){
if(!flag[i])continue;
cntq[x]=(cntq[x]+cntq[a[i].to])%mod;
}
}
}
inline void sol(int qq){
spfa(qq);topu(qq);
for(register int i=1;i<=m;++i){
if(flag[i])ans[i]=(ans[i]+1ll*cntm[a[i].fr]*cntq[a[i].to]%mod)%mod;
}
}
inline void add(int qq,int mm,int l){
a[++cnt].fr=qq;
a[cnt].next=head[qq];
head[qq]=cnt;
a[cnt].to=mm;
a[cnt].w=l;
}
int main()
{
read(n);read(m);
for(int i=1;i<=m;i++){
int x,y,j;
read(x);read(y);read(j);
add(x,y,j);
}
for(int i=1;i<=n;i++)sol(i);
for(int i=1;i<=m;i++){
printf("%d\n",ans[i]);
}
return 0;
}