P4159 [SCOI2009] 迷路
阿新 • • 發佈:2021-08-13
矩陣加速求圖上路徑計數。
Problem
給一個\(n\)個節點\(m\)條邊的帶權有向圖。求從\(1\to n\)的長度為\(t\)的路徑條數。對\(2009\)取模。
\(2 \le n \le 10,1 \le t \le 10^9\)
值得一提的是,此題的輸入格式:
說明邊權\(\le 9\)。
Solution
Thinking 1
考慮邊權都為\(1\)怎麼做。
設\(f[t][i][j]\)為長度為\(t\),\(i \to j\)的路徑數。
易得:
這就是矩陣乘法板子。易得\(f[t] = f[1]^t\)
Thinking 2
考慮一條\(u \to v\),長度為\(w\)的邊。
可以把它拆成\(w\)條長度為\(1\)的邊,然後中間用拆的點表示。
然後變成\(10n \cdot 10n\)的矩陣搞。
# include <bits/stdc++.h> using namespace std; const int mod = 2009; int n,t; struct Matrix { int a[105][105]; void init(int x = 0) { for(int i = 1; i <= n * 10; i++) { for(int j = 1; j <= n * 10; j++) { a[i][j] = (i == j) ? x : 0; } } return; } }A; int calc(int i,int j) {return (i - 1) * 10 + j;} Matrix operator * (const struct Matrix &x,const struct Matrix &y) { Matrix ans; ans.init(); for(int i = 1; i <= n * 10; i++) { for(int j = 1; j <= n * 10; j++) { for(int k = 1; k <= n * 10; k++) { ans.a[i][j] = (ans.a[i][j] + x.a[i][k] * y.a[k][j]) % mod; } } } return ans; } Matrix qpow(Matrix x,int p) { Matrix ans; ans.init(1); while(p) { if(p & 1) ans = ans * x; p >>= 1; x = x * x; } return ans; } int main(void) { scanf("%d%d",&n,&t); for(int i = 1; i <= n; i++) { for(int j = 1; j <= 9; j++) { A.a[calc(i,j)][calc(i,j + 1)] = 1; } } for(int i = 1; i <= n; i++) { char s[12]; scanf("%s", s + 1); for(int j = 1; j <= n; j++) { int x = s[j] - '0'; if(!x) continue; A.a[calc(i,x)][calc(j,1)] = 1; } } Matrix ans = qpow(A,t); printf("%d\n",ans.a[1][calc(n,1)]); return 0; }