題解 洛谷P6413 [COCI2008-2009#3] NAJKRACI
阿新 • • 發佈:2021-06-23
分析
計算出最短路後,一條邊是最短路的一部分,當且僅當起點的 \(f\) 值加上該邊邊權等於終點的 \(f\) 值,所以跑最短路後,對 \(m\) 條邊進行判定,滿足該條件的加入最短路圖。
加入後進行拓撲排序,計算以該邊作為終點的最短路個數 \(cntz\),和該邊作為起點的最短路 \(cntq\),易證兩子問題的計算互為倒序,拓撲排序只需跑起點到終點即可,跑的過程中記錄順序,在倒著順序把 \(cntz\) 加回來,最後將兩值相乘,即為答案。
即每一次 \(cntm_v+=cntm_u\),\(cntq_u+=cntq_v\),\(ans_i+=cntm_i \times cntq_i\)
另外值得注意的是,因為是不斷換起點跑最短路,\(dijkstra\) 的複雜度可能因 \(memset\) 過多而時間較長,\(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)); 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; }