POJ3613 Cow Relays
阿新 • • 發佈:2020-12-26
題目連結:POJ3613 Cow Relays
題目大意:
一張圖有 \(T\) 條邊,邊兩個端點的序號 \(\in [1,1000]\) ,求起點 \(S\) 到 \(E\) 恰好經過 \(N\) 條邊的最短路。
\(1\leq T\leq 100\) , \(1\leq N\leq 1000000\)
思路:
經典題,點的數量最多為 \(2T\) ,先離散化,考慮矩陣乘法:
設 \(M*M\) 的矩陣 \(A^k\) , \((A^k)[i,j]\) 為從 \(i\) 到 \(j\) 恰好經過 \(k\) 條邊的最短路長度,那麼應該有:
其中 \(A^1\) 就是鄰接矩陣, \((A^N)[s][e]\) 即為答案。
注意到這個過程滿足結合律,其實就是將加法改為取 \(min\) 的矩陣乘法,那麼我們就可以矩陣快速冪了,時間複雜度 \(O(T^3logN)\) 。
細節:
- 矩陣定義時可以在外面套一個結構體,這樣就不用糾結陣列指標之類的問題了,可以直接引用和複製。
Code:
#include<iostream> #include<algorithm> #include<vector> #include<cstring> #define rep(i,a,b) for(int i=a;i<=b;i++) #define per(i,a,b) for(int i=b;i>=a;i--) #define lb lower_bound #define T 205 #define hash Hash #define Inf 0x3f3f3f3f using namespace std; struct edge{ int len,u,v; }E[T]; struct matrix{ int a[T][T]; void init(){ rep(i,0,T-1)rep(j,0,T-1)a[i][j]=Inf; } }; matrix mat,opt,c; int n,t,s,e; int hash[T]; void mul(matrix &a,matrix b){ c.init(); rep(i,0,t-1)rep(j,0,t-1)rep(k,0,t-1) c.a[i][j]=min(c.a[i][j],a.a[i][k]+b.a[k][j]); a=c; } int main(){ cin>>n>>t>>s>>e; rep(i,0,t-1){ cin>>E[i].len>>E[i].u>>E[i].v; hash[2*i]=E[i].u,hash[2*i+1]=E[i].v; } sort(hash,hash+2*t); int m=unique(hash,hash+2*t)-hash; opt.init(); rep(i,0,t-1){ int u=lb(hash,hash+m,E[i].u)-hash; int v=lb(hash,hash+m,E[i].v)-hash; opt.a[u][v]=opt.a[v][u]=E[i].len; } mat=opt; n--; for(;n;n>>=1){ if(n&1)mul(mat,opt); mul(opt,opt); } s=lb(hash,hash+m,s)-hash,e=lb(hash,hash+m,e)-hash; cout<<mat.a[s][e]; return 0; }