您的位置:首页 > 其它

【矩阵乘法】迷路

2012-03-08 22:23 260 查看
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;
//}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  matrix 算法 联想 存储 ini c