1. 程式人生 > >洛谷P2505 [HAOI2012]道路(最短路計數)

洛谷P2505 [HAOI2012]道路(最短路計數)

== true show code mes main 自己 mod target

傳送門

早上模擬賽考這題,結果竟然看錯題目了orz

然後下午看完題解自己做的時候空間開小了白WA了好久orz

首先,如果以$S$為起點,一條邊$(u,v)$在最短路上,則$dis[u]+edge[i]=dis[v]$

那麽我們先以每個點為起點跑一遍最短路

每一次跑完最短路,對於一條邊$i$,考慮它的經過次數

首先得滿足上面那個條件,然後設$a[u]$表示從$S$走到$u$的最短路的方案,$v$表示經過$v$的最短路的方案

那麽$ans[i]+=a[u]*b[v]$

$a$數組可以一遍拓撲排序順便求出來,$b$數組可以用記憶化搜索搞出來

然後每一次跑完最短路都求出$a$和$b$,如果一條邊出現在了這一次的最短路圖中,就更新它的答案

 1 //minamoto
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<queue>
 6 #define ll long long
 7 using namespace std;
 8 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
 9 char buf[1<<21],*p1=buf,*p2=buf;
10 template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;} 11 inline int read(){ 12 #define num ch-‘0‘ 13 char ch;bool flag=0;int res; 14 while(!isdigit(ch=getc())) 15 (ch==-)&&(flag=true); 16 for(res=num;isdigit(ch=getc());res=res*10+num);
17 (flag)&&(res=-res); 18 #undef num 19 return res; 20 } 21 const int N=1505,M=5005,mod=1e9+7; 22 struct node{ 23 int u,dis; 24 node(){} 25 node(int u,int dis):u(u),dis(dis){} 26 inline bool operator <(const node &b)const 27 {return dis>b.dis;} 28 }; 29 priority_queue<node> q; 30 int head[N],Next[M],ver[M],edge[M],from[M],tot,n; 31 ll ans[M],a[M],b[M];int dis[N],vis[M],d[N]; 32 int st[N],h,t,m; 33 inline void add(int u,int v,int e){ 34 ver[++tot]=v,Next[tot]=head[u],head[u]=tot,edge[tot]=e,from[tot]=u; 35 } 36 void dijkstra(int s){ 37 memset(dis,0x3f,sizeof(dis)); 38 memset(vis,0,sizeof(vis)); 39 dis[s]=0,q.push(node(s,0)); 40 while(!q.empty()){ 41 int u=q.top().u;q.pop(); 42 if(vis[u]) continue; 43 vis[u]=1; 44 for(int i=head[u];i;i=Next[i]){ 45 int v=ver[i]; 46 if(cmin(dis[v],dis[u]+edge[i])) 47 q.push(node(v,dis[v])); 48 } 49 } 50 } 51 inline void inita(int s){ 52 for(int u=1;u<=n;++u) 53 for(int i=head[u];i;i=Next[i]) 54 if(dis[ver[i]]==dis[u]+edge[i]) ++d[ver[i]]; 55 st[h=t=1]=s; 56 while(h<=t){ 57 int u=st[h++]; 58 for(int i=head[u];i;i=Next[i]){ 59 int v=ver[i]; 60 if(dis[v]==dis[u]+edge[i]){ 61 --d[v],(a[v]+=a[u])%=mod; 62 if(!d[v]) st[++t]=v; 63 } 64 } 65 } 66 } 67 void initb(int u){ 68 b[u]=1; 69 for(int i=head[u];i;i=Next[i]){ 70 int v=ver[i]; 71 if(dis[v]==dis[u]+edge[i]){ 72 vis[i]=1; 73 if(!b[v]) initb(v); 74 (b[u]+=b[v])%=mod; 75 } 76 } 77 } 78 int main(){ 79 // freopen("testdata.in","r",stdin); 80 n=read(),m=read(); 81 for(int i=1,u,v,e;i<=m;++i) 82 u=read(),v=read(),e=read(),add(u,v,e); 83 for(int i=1;i<=n;++i){ 84 dijkstra(i); 85 memset(a,0,sizeof(a)); 86 memset(b,0,sizeof(b)); 87 memset(vis,0,sizeof(vis)); 88 a[i]=1,inita(i),initb(i); 89 for(int j=1;j<=m;++j) 90 if(vis[j]) (ans[j]+=a[from[j]]*b[ver[j]])%=mod; 91 } 92 for(int i=1;i<=m;++i) printf("%lld\n",ans[i]); 93 return 0; 94 }

洛谷P2505 [HAOI2012]道路(最短路計數)