BZOJ 1297 [SCOI2009]迷路 递推 矩阵乘法

来源:互联网 发布:朴素贝叶斯算法详解 编辑:程序博客网 时间:2024/05/11 05:13

题目大意:有向图有 n(n<=10) 个节点,有若干条有向边,经过一条边需要花费一些时间。从节点 0 出发,必须恰好在 T(T<=1000000000) 时刻到达节点 N-1。 总共有多少种不同的路径? 注意:不能在某个节点逗留,且通过某有向边的时间严格为给定的时间。

若知道第i秒的方案,可以推出后面10秒内的部分方案。设第i秒的经过节点j的方案数为f(i,j),则f(i,j)=sigma{f(i-k,t)} ,其中t到j有一条需要消耗k个单位时间的单向边。很明显的递推,可是T很大,想到用矩阵快速幂加速递推。

定义方案矩阵mat为第i秒的经过各点的方案数,可是递推时会可能会更新后10秒的状态,而一个矩阵只能代表1秒。这里采用将一个点分裂成10个点的方法,第一个点代表第i秒经过节点j的方案数,另外9个点为临时存储方案的点,表示从j出发已经走了k秒。
例如从j到t需要x秒,已知i-1秒的状态想求第i秒的状态,那么第i秒经过节点t的方案中就有一部分是在i-1秒时从节点j已经走了x-1秒的方案。以此类推,详见代码。

#include <cstdio>]#include <cstring>#define N 100#define MOD 2009using namespace std;struct Matrix {    int a[N+5][N+5];    Matrix() { memset(a,0,sizeof a); }    Matrix operator * (const Matrix& rhs) const {        Matrix tmp;        for(int i=0;i<100;i++)            for(int j=0;j<100;j++)                for(int k=0;k<100;k++)                    (tmp.a[i][j]+=a[i][k]*rhs.a[k][j])%=MOD;        return tmp;    }}mat,ini,trans;Matrix f_pow(Matrix x,int y) {    Matrix tmp=ini;    while(y) {        if(y&1) tmp=tmp*x;        x=x*x;        y>>=1;    }    return tmp;}char a[15][15];int main() {    int n,m;    scanf("%d%d",&n,&m);    for(int i=0;i<n;i++) scanf("%s",a[i]);    for(int i=0;i<n;i++)        for(int j=1;j<10;j++)            trans.a[i*10+j-1][i*10+j]=1;    for(int i=0;i<n;i++)        for(int j=0;j<n;j++) {            int x=a[i][j]-'0';            if(!x) continue;            trans.a[i*10+x-1][j*10]=1;        }    for(int i=0;i<100;i++) ini.a[i][i]=1;    mat.a[0][0]=1;    mat=mat*f_pow(trans,m);    printf("%d\n",mat.a[0][(n-1)*10]);    return 0;}
0 0
原创粉丝点击