1. 程式人生 > >B1297 [SCOI2009]迷路 矩陣

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 */