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

 

posted @ 2018-12-09 15:55  DukeLv  阅读(226)  评论(0编辑  收藏  举报