【矩陣乘法】迷路
SCOI2009第二試第三題
迷路
(road.pas/in/out)
【問題描述】
windy在有向圖中迷路了。
該有向圖有 N 個節點,windy從節點 0 出發,他必須恰好在 T 時刻到達節點 N-1。
現在給出該有向圖,你能告訴windy總共有多少種不同的路徑嗎?
注意:windy不能在某個節點逗留,且通過某有向邊的時間嚴格為給定的時間。
【輸入格式】
輸入檔案road.in第一行包含兩個整數,N T。
接下來有 N 行,每行一個長度為 N 的字串。
第i行第j列為'0'表示從節點i到節點j沒有邊。
為'1'到'9'表示從節點i到節點j需要耗費的時間。
【輸出格式】
輸出檔案road.out包含一個整數,可能的路徑數,這個數可能很大,只需輸出這個數除以2009的餘數。
【輸入樣例一】
2 2
11
00
【輸出樣例一】
1
【樣例解釋一】
0->0->1
【輸入樣例二】
5 30
12045
07105
47805
12024
12345
【輸出樣例二】
852
【資料規模和約定】
30%的資料,滿足 2 <= N <= 5 ; 1 <= T <= 30 。
100%的資料,滿足 2 <= N <= 10 ; 1 <= T <= 1000000000 。
看著就很熟悉,聯想起了過去講過的矩陣乘法的應用,求T時刻到達某一點的總方案數。
過去的模型時單位時間內能走過1個格子。
這道題不一樣,不同的路線花的時間不一樣。
我沒有想出解決方案來,OJ指出了方向,拆點。
O(lgn)的複雜度,已經到極限了。
一開始走了很多彎路,在過程中受到指點,改正了很多地方
1)一開始拆點的方法不好,用了慣用的在所有點之後附加點的方法(平常超級源超級匯的處理方法,拆點我一般都用連結串列,但是此題不行,因為是矩陣),一直弄不好。WJJ指出了更好的方法,即給每一個點開一段連續的記憶體,儲存該點和它拆的點。因此我感到,不僅要分析演算法的優劣,分析儲存方式也很重要,如果因為儲存方式不好,而導致實現好演算法實現困難就得不償失了。
2)我一開始打快速冪的模板很容易就直接寫矩陣的類了,結果很難打。最好不要寫類。。
3)單位矩陣是主對角線上為1,我以為是全是1
4)快速冪的返回值沒有用,記得返回,記得要用
。。。。。。。。未完待定
#include <cstdio>
long target;
struct Matrix
{
long size;
long map[110][110];
// long operator[](long i,long j){return map[i][j];}
Matrix(long M2[110][110],long _size)
{
size = _size;
for (long i=0;i<size;i++)
{
for (long j=0;j<size;j++)
{
map[i][j] = M2[i][j];
}
}
}
// Matrix operator*(Matrix& M2)
// {
// long _m[110][110];
// for (long i=1;i<size+1;i++)
// {
// for (long k=1;k<size+1;k++)
// {
// for (long j=1;j<size+1;j++)
// {
// _m[i][j] += map[i][k]*M2.map[k][j];
// }
// }
// }
// return Matrix(_m,size);
// }
void operator*=(Matrix& M2)
{
long _m[110][110];
for (long i=0;i<size;i++)
for (long j=0;j<size;j++)
_m[i][j] = 0;
for (long i=0;i<size;i++)
{
for (long j=0;j<size;j++)
{
for (long k=0;k<size;k++)
{
(_m[i][j] += map[i][k]*M2.map[k][j])%= 2009;
}
}
}
for (long i=0;i<size;i++)
for (long j=0;j<size;j++)
map[i][j] = _m[i][j];
}
// void operator%=(long c)
// {
// for (long i=0;i<size;i++)
// {
// for (long j=0;j<size;j++)
// {
// map[i][j] %= c;
// }
// }
// }
long get(long i,long j){return map[i][j];}
Matrix(long _num,long _size)
{
size = _size;
for (long i=0;i<size;i++)
{
map[i][i] = _num;
}
}
void operator=(Matrix& M2)
{
size = M2.size;
for (long i=0;i<size;i++)
{
for (long j=0;j<size;j++)
{
map[i][j] = M2.map[i][j];
}
}
}
};
long _map[110][110];
long cnt;
template<typename TYPE>
void qpower(TYPE &a,long b)
{
TYPE pow = a;
TYPE ans (1,cnt);
while (b)
{
if (b&1){ans*=pow;}
pow*=pow;
b >>= 1;
}
a = ans;
}
long n;long t;
int main()
{
freopen("road.in","r",stdin);
freopen("road.out","w",stdout);
scanf("%ld%ld",&n,&t);
cnt = n*9;
for (long i=0;i<n;i++)
{
scanf("\n");
for (long j=0;j<n;j++)
{
char tmp ;
scanf("%c",&tmp);
tmp -= '0';
if (tmp == 1)
{
_map[i*9][j*9] = 1;
}
else if (tmp > 1)
{
_map[i*9][j*9+tmp-1] = 1;
for (long k=j*9+tmp-1;k>j*9;k--)
{
_map[k][k-1] = 1;
}
}
}
}
Matrix map(_map,cnt);
qpower(map,t);
#ifdef Debug
// printf("\t ");
// for (long i=0;i<n*9+1;i++)
// printf("%ld\t",i);
// printf("\n");
// for (long i=0;i<n*9+1;i++)
// printf("-----");
//
// for (long i=0;i<n*9+1;i++)
// {
// printf("\n%ld\t|",i);
// for (long j=0;j<n*9+1;j++)
// {
// if (map.get(i,j) == 1)
// printf("%ld\t",1);
// else
// printf(" \t");
// }
// }
#endif
printf("%ld",map.get(0,n*9-9)%2009);
return 0;
}
//long _ma[3][3] = {{1,2,0},{0,1,1},{0,0,1}};
//int main()
//{
// Matrix m1(1,3);
// Matrix m2(1,3);
// Matrix m3 = m1;
// m3 *= m2;
// return 0;
//}