藍書(演算法競賽進階指南)刷題記錄——POJ3613 Cow Replays(最短路+矩陣乘法)
阿新 • • 發佈:2018-11-10
題目:POJ3613.
題目大意:給出一張圖,然你求出經過N條邊後,S到T的最短路.
這道題一開始覺得挺容易的,用f[i][j]表示從起點到點i經過j的最短路,不斷更新就可以了.
但是突然發現數據巨大根本跑不過去...
然後就開始看書上的題解了...
書上居然要用矩陣乘法,好難寫的要不我放棄吧...
書上說的思路就是先離散化,然後用floyd演算法用f[i][j][k]表示從i到j的經過k條邊的最短路.
那麼我們將轉移方程列出來:
然後我們會發現,每一次轉移時用來更新的邊權都是一樣的,而且點的範圍特別小,更新的次數特別多.
所以我們可以想到矩陣乘法剛好滿足這幾個性質,而且f其實就是一個矩陣!
那麼其實f就是一個“廣義矩陣乘法”,很明顯廣義矩陣乘法是滿足結合律的,所以我們就可以用快速冪優化遞推.時間複雜度,由於2P個點不一定能跑滿,所以這個演算法是能過的.
程式碼如下:
#include<iostream> #include<cstdio> using namespace std; #define Abigail inline void typedef long long LL; const int P=1000,T=100,INF=(1<<29)-1; int num[P+9],ord[P+9],top; int s,t,x[T+9],y[T+9],v[T+9]; int n,m; struct matrix{ int a[T*2+9][T*2+9],n,m; matrix(){ n=m=0; for (int i=0;i<T*2+9;i++) for (int j=0;j<T*2+9;j++) a[i][j]=INF; } matrix operator * (const matrix &p)const{ matrix tmp=matrix(); tmp.n=n;tmp.m=p.m; for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) for (int k=1;k<=p.m;k++) tmp.a[i][k]=min(tmp.a[i][k],a[i][j]+p.a[j][k]); return tmp; } }a; matrix power(matrix a,int k){ matrix s=a;k--; for (;k;k>>=1,a=a*a) if (k&1) s=s*a; return s; } Abigail into(){ scanf("%d%d%d%d",&n,&m,&s,&t); for (int i=1;i<=m;i++){ scanf("%d%d%d",&v[i],&x[i],&y[i]); num[x[i]]++;num[y[i]]++; } } Abigail work(){ for (int i=1;i<=1000;i++) if (num[i]) ord[i]=++top; s=ord[s];t=ord[t]; for (int i=1;i<=m;i++) a.a[ord[x[i]]][ord[y[i]]]=a.a[ord[y[i]]][ord[x[i]]]=min(a.a[ord[x[i]]][ord[y[i]]],v[i]); a.n=a.m=top; a=power(a,n); } Abigail outo(){ printf("%d\n",a.a[s][t]); } int main(){ into(); work(); outo(); return 0; }