B1297 [SCOI2009]迷路 矩阵
这个题我觉得很有必要写一篇博客。首先,我们需要知道,假如一个邻接矩阵只有0/1构成,那么它自己的n次方就是走n步之后的方案数。但这个题还有2~9咋办呢。我们观察发现,这个题只有10个点,而且边权<=9我们可以想到拆点这个小操作。把每个点拆成9个点,点内连1的边,点外分别连到相应的权值就行了。
题干:
windy在有向图中迷路了。 该有向图有 N 个节点,windy从节点 0 出发,他必须恰好在 T 时刻到达节点 N-1。 现在给出该有向图,你能告诉windy总共有多少种不同的路径吗? 注意:windy不能在某个节点逗留,且通过某有向边的时间严格为给定的时间。
代码:
#include<iostream> #include<cstdio> #include<cmath> #include<ctime> #include<queue> #include<algorithm> #include<cstring> using namespace std; #define duke(i,a,n) for(register int i = a;i <= n;i++) #define lv(i,a,n) for(register int i = a;i >= n;i--) #define clean(a) memset(a,0,sizeof(a)) const int INF = 1 << 30; const int mod = 2009; typedef long long ll; typedef double db; template <class T> void read(T &x) { char c; bool op = 0; while(c = getchar(), c < '0' || c > '9') if(c == '-') op = 1; x = c - '0'; while(c = getchar(), c >= '0' && c <= '9') x = x * 10 + c - '0'; if(op) x = -x; } template <class T> void write(T x) { if(x < 0) putchar('-'), x = -x; if(x >= 10) write(x / 10); putchar('0' + x % 10); } int m,T; struct Mat { int a[105][105],n; Mat() { n = m * 9; clean(a); } void I() { // cout<<n<<endl; duke(i,1,n) { a[i][i] = 1; } } inline Mat operator * (const Mat &oth) { Mat res; // cout<<n<<endl; duke(i,1,n) { duke(j,1,n) { int sum = 0; duke(k,1,n) { sum = (sum + a[i][k] * oth.a[k][j]) % mod; } res.a[i][j] = sum; } } return res; } }A,B; Mat qpow(Mat a,int k) { Mat c; c.I(); // cout<<k<<endl; while(k) { if(k % 2 == 1) { c = c * a; } a = a * a; k >>= 1; // cout<<k<<endl; } return c; } char s[105]; int main() { read(m);read(T); A.n = m * 9; duke(i,1,m) { duke(j,1,8) A.a[9 * (i - 1) + j][9 * (i - 1) + j + 1] = 1; } duke(i,1,m) { scanf("%s",s); duke(j,1,m) { if(s[j - 1] > '0') A.a[9 * (i - 1) + s[j - 1] - '0'][9 * (j - 1) + 1] = 1; } } // cout<<"??"<<endl; B = qpow(A,T); printf("%d\n",B.a[1][m * 9 - 8]); return 0; } /* 2 2 11 00 */
只想找一个不会伤害我的人