1. 程式人生 > >【BZOJ2750】【HAOI2012】道路(最短路+拓撲)

【BZOJ2750】【HAOI2012】道路(最短路+拓撲)

容易想到列舉所有起點 做最短路 然後列舉邊統計次數

一條邊(x,y)的貢獻 肯定是 s到x最短路的方案數 乘上 s到其他點但經過了y的最短路

對於前者

每個點可以從前一個點遞推過來 只要滿足dis[vis]==dis[now]+edge[u].val 當一個點被所有入邊都統計了一次後 就可以搜他了(拓撲思想)

對於後者

每個點從後一個點遞推過來

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define N 5505
#define M 5005
#define ll long long
using namespace std;
const int mod=1000000007; 
template <class T>
inline void read(T &x)
{
    x=0;
    static char ch=getchar();
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
}
int n,m,first[N],tot,dis[N];
ll a[N],b[N],ans[N];
struct Edge
{
    int from,to,next,val;
}edge[M];
inline void addedge(int x,int y,int z)
{
    tot++;
    edge[tot].from=x; edge[tot].to=y; edge[tot].next=first[x]; edge[tot].val=z; first[x]=tot;
}
bool visit[N],onroad[N];
typedef pair<int,int> Pair;
void Dijkstra(int s)
{
    priority_queue<Pair,vector<Pair>,greater<Pair> > heap;
    memset(dis,0x3f,sizeof(dis)); memset(visit,false,sizeof(visit));
    heap.push(make_pair(0,s)); dis[s]=0;
    while(!heap.empty())
    {
        int now=heap.top().second;
        heap.pop();
        if(visit[now])  continue;
        visit[now]=true;
        for(int u=first[now];u;u=edge[u].next)
        {
            int v=edge[u].to;
            if(dis[now]+edge[u].val<dis[v])
            {
                dis[v]=dis[now]+edge[u].val;
                heap.push(make_pair(dis[v],v));
            }
        }
    }
}
int in[N];
void dfs1(int now)
{
    visit[now]=true;
    for(int u=first[now];u;u=edge[u].next)
    {
        int vis=edge[u].to;
        if(dis[vis]==dis[now]+edge[u].val)  //說明在最短路上
        {
            in[vis]++;
            if(visit[vis])  continue;
            dfs1(vis);
        } 
    }
}
void dfs2(int now)
{
    for(int u=first[now];u;u=edge[u].next)
    {
        int vis=edge[u].to;
        if(dis[vis]==dis[now]+edge[u].val)
        {
            onroad[u]=true;
            a[vis]=(a[vis]+a[now])%mod;
            in[vis]--;
            if(in[vis]==0)  dfs2(vis); 
        }
    }
}
void dfs3(int now)
{
    b[now]=1;
    for(int u=first[now];u;u=edge[u].next)
    {
        int vis=edge[u].to;
        if(dis[now]+edge[u].val==dis[vis])
        {
            if(!b[vis]) dfs3(vis);  //最短路沒有環 放心dfs 
            b[now]=(b[now]+b[vis])%mod;
        }
    }
}
void Init()
{
    memset(onroad,false,sizeof(onroad));
    memset(a,0,sizeof(a));
    memset(b,0,sizeof(b));
    memset(in,0,sizeof(in));
}
int main()
{
    read(n),read(m);
    for(int i=1,x,y,z;i<=m;i++)
    {
        read(x),read(y),read(z);
        addedge(x,y,z);
    }
    for(int i=1;i<=n;i++)
    {
        Init();
        Dijkstra(i);
        memset(visit,0,sizeof(visit));
        dfs1(i);    //來自最短路上的入度
        a[i]=1;
        dfs2(i);    //i到每個點最短路的方案數
        dfs3(i);    //i製造的最短路經過每個點的數量 
        for(int j=1;j<=m;j++)   if(onroad[j])   ans[j]=(ans[j]+a[edge[j].from]*b[edge[j].to]%mod)%mod;
    }
    for(int i=1;i<=m;i++)   cout<<ans[i]<<'\n';
    return 0;
}