[USACO07NOV]Cow Relays G
阿新 • • 發佈:2020-10-12
題目大意
給出一張無向連通圖(點數小於1000),求S到E經過k條邊的最短路。
演算法
這是之前國慶模擬賽的題
因為懶 所以就只挑一些題寫部落格
在考場上寫了個dp 然後水到了50分 出考場和神仙們一問才知道是lyd藍書原題
我們考慮有兩個floyd的矩陣 A代表走了x條邊的矩陣 B代表走了y條邊的矩陣
那麼我們想求出C這個代表走了(x + y)這個矩陣的值呢
我們考慮這麼一個式子
\(C[i][j] = min( A[i][k] + B[k][j] )\)
然後我們發現 其中\(A[i][k] + B[k][j]\)這個式子和矩陣乘的式子很像
我們把矩陣乘的 \(+\) 改成 \(min\) 即可
那麼我們可以考慮將初始給定A矩陣(也就是走了一次的floyd矩陣)進行n - 1次轉移
\(A_n[i][j] = (A[i][j]) ^ {n - 1}\)
然後用快速冪就可以實現了
程式碼
#include <bits/stdc++.h> using namespace std; int num[1000005]; int n,s,t,e,tol; struct map { int a[500][500]; map operator * (const map &x) const //過載運算子,一會兒要用 { map c; memset(c.a,0x3f3f3f3f,sizeof(c.a));//取min,顯然置大數 for(int k=1;k<=tol;k++) for(int i=1;i<=tol;i++) for(int j=1;j<=tol;j++) c.a[i][j]=min(c.a[i][j],a[i][k]+x.a[k][j]); return c; } }dis,ans; void init() { memset(dis.a,0x3f3f3f3f,sizeof(dis.a)); int x,y,z; cin>>n>>t>>s>>e; for(int i=1;i<=t;i++) { scanf("%d %d %d",&x,&y,&z); if(!num[y]) //這裡做一個離散化 num[y]=++tol; if(!num[z]) num[z]=++tol; dis.a[num[y]][num[z]]=dis.a[num[z]][num[y]]=x; } } void doit() //快速冪 { n--; ans=dis; while(n) { if(n&1) ans=ans*dis; dis=dis*dis; n>>=1; } } int main() { init(); doit(); cout<<ans.a[num[s]][num[e]]; }