Problem
给一个(n)个节点(m)条边的带权有向图。求从(1 o 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 o j)的路径数。
易得:
[f[t][i][j] = sum_{k = 1} ^ n f[t - 1][i][k] cdot f[1][k][j]
]
这就是矩阵乘法板子。易得(f[t] = f[1]^t)
Thinking 2
考虑一条(u o 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
",ans.a[1][calc(n,1)]);
return 0;
}