bzoj1297 [SCOI2009]迷路

1297: [SCOI2009]迷路

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 1366  Solved: 976
[Submit][Status][Discuss]

Description

windy在有向图中迷路了。 该有向图有 N 个节点,windy从节点 0 出发,他必须恰好在 T 时刻到达节点 N-1。 现在给出该有向图,你能告诉windy总共有多少种不同的路径吗? 注意:windy不能在某个节点逗留,且通过某有向边的时间严格为给定的时间。

Input

第一行包含两个整数,N T。 接下来有 N 行,每行一个长度为 N 的字符串。 第i行第j列为'0'表示从节点i到节点j没有边。 为'1'到'9'表示从节点i到节点j需要耗费的时间。

Output

包含一个整数,可能的路径数,这个数可能很大,只需输出这个数除以2009的余数。

Sample Input

【输入样例一】
2 2
11
00

【输入样例二】
5 30
12045
07105
47805
12024
12345


Sample Output

【输出样例一】
1

【样例解释一】
0->0->1

【输出样例二】
852

HINT

 

30%的数据,满足 2 <= N <= 5 ; 1 <= T <= 30 。 100%的数据,满足 2 <= N <= 10 ; 1 <= T <= 1000000000 。

分析:有一道比较经典的题,求恰好经过k条边的最短路,这道题可以用矩阵乘法来做,这道题和那道题是类似的,不过边权有变化,那怎么办呢?拆点就好了,因为边权最多为9,所以每个点拆成9个点,上一个点向下一个点连边权为1的边,点与点之间连边的话,边权为几,就连向拆成的第几个点,最后矩阵快速幂就解决了.
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int mod = 2009;

int n, t, maxn,b[200][200],ans[200][200],temp[200][200];

int c(int x, int y)
{
    return (y - 1) * n + x;
}

void mul1()
{
    memset(temp, 0, sizeof(temp));
    for (int i = 1; i <= maxn; i++)
        for (int j = 1; j <= maxn; j++)
            for (int k = 1; k <= maxn; k++)
            {
                temp[i][j] += ans[i][k] * b[k][j];
                temp[i][j] %= mod;
            }
    memcpy(ans, temp, sizeof(ans));
}

void mul2()
{
    memset(temp, 0, sizeof(temp));
    for (int i = 1; i <= maxn; i++)
        for (int j = 1; j <= maxn; j++)
            for (int k = 1; k <= maxn; k++)
            {
                temp[i][j] += b[i][k] * b[k][j];
                temp[i][j] %= mod;
            }
    memcpy(b, temp, sizeof(b));
}

void qpow(int b)
{
    while (b)
    {
        if (b & 1)
            mul1();
        b >>= 1;
        mul2();
    }
}

int main()
{
    scanf("%d%d", &n, &t);
    for (int i = 1; i <= n; i++)
        for (int j = 2; j <= 9; j++)
            b[c(i, j)][c(i, j - 1)] = 1;

    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            int x;
            scanf("%1d", &x);
            if (!x)
                continue;
            b[i][c(j, x)] = 1;
        }
    }
        maxn = n * 9;
        for (int i = 1; i <= maxn; i++)
            ans[i][i] = 1;
        qpow(t);
        printf("%d\n", ans[1][n]);

    return 0;
}

 

posted @ 2017-09-18 21:23  zbtrs  阅读(179)  评论(0编辑  收藏  举报