【矩阵乘法】迷路
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;
//}
迷路
(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;
//}
相关文章推荐
- [Bzoj1297][Scoi2009 ]迷路 (矩阵乘法 + 拆点)
- 【bzoj1297】【SCOI2009】【迷路】【矩阵乘法】
- [SCOI2009]BZOJ1297 迷路 - 矩阵乘法
- 【bzoj1297】[SCOI2009]迷路 矩阵乘法
- [bzoj1297][DP][矩阵乘法]迷路
- bzoj1297: [SCOI2009]迷路 矩阵乘法
- bzoj1297: [SCOI2009]迷路(矩阵乘法+拆点)
- BZOJ 1297 SCOI2009 迷路 矩阵乘法
- 【矩阵乘法】【SCOI2009】迷路
- BZOJ 1297 [SCOI2009]迷路 递推 矩阵乘法
- BZOJ1297: [SCOI2009]迷路 矩阵乘法
- B20J_1297_[SCOI2009]迷路_矩阵乘法
- 【矩阵乘法】广义斐波那契数列
- NYOJ 623 矩阵乘法
- 算法系列-----矩阵(四)-------------矩阵的乘法
- 动态规划 的方法求矩阵乘法的最少计算加括号方式
- 手把手教你用Execel计算两个矩阵的乘法
- 【矩阵乘法】Fibonacci数列 WikiOI 1732/1250
- 十个利用矩阵乘法解决的经典题目
- 矩阵乘法的四种理解方式