BZOJ1297 迷路 - 矩阵的幂

传送门

题目大意:

输入n(点的数量),t(时间),和一个n*n的矩阵,第i行第j列表示第i个节点到第j个节点有一条matrix[i]j时间的边,若为0则没有边,问从1到n恰好经过t时间的方案数有多少种?

题目分析:

矩阵的幂与路径的联系:若i到j有一条边权为1的边,那么matrix[i][j]=1,\(matrix^k\)中的[1][n]即代表1到n距离恰好k的方案数(同样也可以表示:i到j有一条边,1到n的经过边数恰好为k的方案数。)
这道题目简化后是:知道i到j有边权为1的边,求x到y的距离为k的方案总数,正是上面提到的。
加上边权后不能套用上边直接求解,因为上面的做法只针对权值为1。但由于一条边的权值只从0~9,那么可以将一个点拆成9个点,若i到j有一条边权为k的边,就相当于从i拆出的第k个节点向j拆出的第1个点连边,i拆出的点之间连边权为1的边,这样\(matrix^t\)的[getkth(i, 1)][getkth(n, 1)]即表示方案数。(getkth表示i拆出的第j个点)

code

#include<bits/stdc++.h>
using namespace std;

namespace IO{
    inline int read(){
        int i = 0, f = 1; char ch = getchar();
        for(; (ch < '0' || ch > '9') && ch != '-'; ch = getchar());
        if(ch == '-') f = -1, ch = getchar();
        for(; ch >= '0' && ch <= '9'; ch = getchar()) i = (i << 3) + (i << 1) + (ch - '0');
        return i * f;
    }
    inline void wr(int x){
        if(x < 0) putchar('-'), x = -x;
        if(x > 9) wr(x / 10);
        putchar(x % 10 + '0');
    }
}using namespace IO;

const int N = 15, Mod = 2009;
int n, T;
struct node{
    int b[N*10][N*10]; //每个点拆成9个
    node(){}
    inline void init(){
        memset(b, 0, sizeof b);
    }
    inline void set(int p, int q, int z){b[p][q] = z;}
    inline void I(){
        //初始化为单位矩阵
        memset(b, 0, sizeof b);
        for(int i = 1; i <= n*9; i++)
            set(i, i, 1);
    }
    inline node operator * (const node &p) const{
        node ret;
        for(int i = 1; i <= n*9; i++)
            for(int j = 1; j <= n*9; j++){
                int sum = 0;
                for(int k = 1; k <= n*9; k++) sum = (sum + b[i][k] * p.b[k][j]) % Mod;
                ret.set(i, j, sum);
            }
        return ret;
    }
    inline node operator ^ (int tt){
        node ret; ret.I();
        node tmp = *this;
        for(; tt; tt >>= 1, tmp = tmp * tmp) if(tt & 1) ret = ret * tmp;
        return ret;
    }
}matrix, ret;

inline int getkth(int x, int k){
    return (x-1) * 9 + k;
}

int main(){
    n = read(), T = read();
    matrix.init(), ret.init();
    for(int i = 1; i <= n; i++) 
        for(int j = 1; j <= 8; j++){
            matrix.set(getkth(i, j), getkth(i, j + 1), 1);
        }
    for(int i = 1; i <= n; i++){
        char c[N]; scanf("%s", c + 1);
        for(int j = 1; j <= n; j++){
            int x = c[j] - '0';
            if(x) matrix.set(getkth(i, x), getkth(j, 1), 1); 
        }
    }
    ret = matrix ^ T;
    wr(ret.b[getkth(1, 1)][getkth(n, 1)]);
    return 0;
}

posted @ 2017-10-19 21:41  CzYoL  阅读(103)  评论(0编辑  收藏  举报