BZOJ-1297 [SCOI2009]迷路(鄰接矩陣的冪)
阿新 • • 發佈:2020-11-20
題目描述
有向圖有 \(n(2\leq n\leq 10)\) 個節點,從節點 \(0\) 出發,必須恰好在 \(t(1\leq t\leq 10^9)\) 時刻到達節點 \(n-1\)。 現在給出該有向圖(邊權 \(1\) ~ \(9\)),求總共有多少種不同的路徑。
分析
首先有一個離散數學中的結論:用鄰接矩陣 \(A\) 存無向圖頂點間的關係,則 \(A^n\) 中的 \(a_{ij}\) 代表點 \(i\) 恰好走 \(n\) 步能到達點 \(j\) 的方案數。
由於邊權範圍為 \(1\) ~ \(9\),不能直接矩陣求冪,所以考慮如何建圖:
\(1.\) 把原圖中的點拆成 \(9\)
\(2.\) 原圖中的點之間連邊:假設原圖中點 \(x\) 與點 \(y\) 的邊權為 \(w\),則連線新圖中的點 \((x-1)\times 9+w\) 和點 \((y-1)\times 9+1\)。
假設原圖的鄰接矩陣為:\(\begin{bmatrix}2&1\\2&0\end{bmatrix}\)
則新圖為:
這樣從點 \(x\) 必須走 \(k\) 條邊才能走到點 \(y\),這時矩陣求冪即可。起點為 \(1\),終點為 \((n-1)\times 9+1\)。
程式碼
#include<bits/stdc++.h> using namespace std; int n,t; const int mod=2009; struct matrix { int mat[310][310]; matrix() { memset(mat, 0, sizeof(mat)); } }A; matrix mul(matrix A,matrix B) { matrix ans; for(int i=1;i<=9*n;i++) for(int j=1;j<=9*n;j++) for(int k=1;k<=9*n;k++) ans.mat[i][j]=(ans.mat[i][j]+A.mat[i][k]*B.mat[k][j])%mod; return ans; } matrix matrix_pow(matrix a,int b) { matrix ans; for(int i=1;i<=9*n;i++) for(int j=1;j<=9*n;j++) ans.mat[i][j]=(i==j); while(b) { if(b&1) ans=mul(ans,a); a=mul(a,a); b>>=1; } return ans; } int a[310][310]; int main() { cin>>n>>t; for(int i=1;i<=n;i++) for(int j=1;j<=8;j++) A.mat[(i-1)*9+j][(i-1)*9+j+1]=1; for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { scanf("%1d",&a[i][j]); if(a[i][j]>0) A.mat[(i-1)*9+a[i][j]][(j-1)*9+1]=1; } } cout<<matrix_pow(A,t).mat[1][(n-1)*9+1]<<endl; return 0; }