【矩阵乘法】迷路

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;
//}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值