【bzoj2750】【HAOI2012】【Road】【最短路+dp】

来源:互联网 发布:淘宝赚钱助手是真的吗 编辑:程序博客网 时间:2024/06/15 20:31

Description

C国有n座城市,城市之间通过m条单向道路连接。一条路径被称为最短路,当且仅当不存在从它的起点到终点的另外一条路径总长度比它小。两条最短路不同,当且仅当它们包含的道路序列不同。我们需要对每条道路的重要性进行评估,评估方式为计算有多少条不同的最短路经过该道路。现在,这个任务交给了你。

Input

第一行包含两个正整数n、m
接下来m行每行包含三个正整数u、v、w,表示有一条从u到v长度为w的道路

Output

输出应有m行,第i行包含一个数,代表经过第i条道路的最短路的数目对1000000007取模后的结果

Sample Input

4 4
1 2 5
2 3 5
3 4 5
1 4 8

Sample Output

2
3
2
1

HINT

数据规模

30%的数据满足:n≤15、m≤30

60%的数据满足:n≤300、m≤1000

100%的数据满足:n≤1500、m≤5000、w≤10000

题解:

把每个点当作起点做spfa。

每次都处理两个数组a[i],b[i]分别表示从起点到点i的最短路数,和从i出发的最短路数。

然后枚举每条边,如果这条边在当前最短路图中。设这条边从i指向j,那就把a[i]*b[j]累加入这条边的答案。

对于这两个数组。我们可以在最短路图上dp一下,或者叫它dfs。

首先b数组比较好做。直接用它的后继结点更新即可.

对于a数组.我们需要先处理一个pre数组.pre[i]表示在最短路图中有多少条边指向i。

然后在做a数组的过程中.我们显然要正着算。

对于一个点,只有它被所有指向它的边的起点更新过之后,再去用这个点更新其他点。

代码:

#include<iostream>#include<cstdio>#include<cstring>#define P 1000000007#define N 2000#define M 5010using namespace std;struct use{int st,en,v;}e[M];int point[N],next[M],x,y,v,n,m,cnt,p[N],dis[N],l[N*100];long long ans[M],a[N],b[N];bool f[N];void add(int x,int y,int v){    next[++cnt]=point[x];point[x]=cnt;    e[cnt].st=x;e[cnt].en=y;e[cnt].v=v;}int spfa(int x){      int h(0),t(1),u;      memset(dis,127/3,sizeof(dis));memset(f,false,sizeof(f));    dis[x]=0;l[t]=x;f[x]=true;      while (h<t){        u=l[++h];f[u]=false;        for (int i=point[u];i;i=next[i])          if (dis[e[i].en]>dis[u]+e[i].v){            dis[e[i].en]=dis[u]+e[i].v;            if (!f[e[i].en]){f[e[i].en]=true;l[++t]=e[i].en;  }          }      }    }  void dfs1(int x){   f[x]=true;   for (int i=point[x];i;i=next[i]){      if (dis[e[i].en]==dis[x]+e[i].v){         p[e[i].en]++;if (!f[e[i].en]) dfs1(e[i].en);      }   }}void dfs2(int x){  for (int i=point[x];i;i=next[i]){     if (dis[e[i].en]==dis[x]+e[i].v){       p[e[i].en]--;(a[e[i].en]+=a[x])%=P;if (!p[e[i].en]) dfs2(e[i].en);      }    }}void dfs3(int x){    b[x]=1;    for (int i=point[x];i;i=next[i]){     if (dis[e[i].en]==dis[x]+e[i].v){       if (!b[e[i].en]) dfs3(e[i].en);(b[x]+=b[e[i].en])%=P;                                                                         }    }}int main(){    scanf("%d%d",&n,&m);    for (int i=1;i<=m;i++){scanf("%d%d%d",&x,&y,&v);add(x,y,v);}    for (int i=1;i<=n;i++){        spfa(i);memset(a,0,sizeof(a));memset(b,0,sizeof(b));memset(f,0,sizeof(f));        dfs1(i);a[i]=1;dfs2(i);dfs3(i);        for (int j=1;j<=m;j++){          if (dis[e[j].en]==dis[e[j].st]+e[j].v) (ans[j]+=a[e[j].st]*b[e[j].en])%=P;        }    }  for (int i=1;i<=m;i++){printf("%lld\n",ans[i]);}}



0 0
原创粉丝点击