BZOJ1297:[SCOI2009]迷路——题解

http://www.lydsy.com/JudgeOnline/problem.php?id=1297

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

我太菜了……参考:http://blog.csdn.net/popoqqq/article/details/41965031

思考当边权为1时,a[i][j]=1可以表示为i到j时间为T=1的方案数为1。

那么显然我们可以求出T=2的a[i][j]=sigma(a[i][k]*a[k][j])。

以此类推求出T时间的a[i][j]……等等,这不显然是矩阵乘法快速幂吗?

那么考虑边权不为1的情况:我们把点拆开强行让他们变成1不就可以了吗。

矩阵自乘T次后答案就是a[0][n-1]。

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=100;
const int p=2009;
char s[N];
int m;
struct node{
    int g[N][N];
};
void buildI(node &a){
    for(int i=1;i<=m;i++){
        for(int j=1;j<=m;j++){
            a.g[i][j]=(i==j);
        }
    }
}
void multi(node x,node y,node &z){
    memset(z.g,0,sizeof(z.g));
    for(int i=1;i<=m;i++){
        for(int j=1;j<=m;j++){
            if(x.g[i][j]){
                for(int k=1;k<=m;k++){
                    z.g[i][k]+=x.g[i][j]%p*y.g[j][k]%p;
                    z.g[i][k]%=p;
                }
            }
        }
    }
    return;
}
node a,b;
void qpow(int k){
    buildI(a);
    while(k){
        if(k&1)multi(a,b,a);
        multi(b,b,b);
        k>>=1;
    }
    return;
}
int solve(int k,int n){
    qpow(k);
    return a.g[1][n]%p;
}
int t,n;
inline int tp(int i,int j){return (j-1)*n+i;}
int main(){
    scanf("%d%d",&n,&t);m=n*9;
    for(int i=1;i<=n;i++){
        for(int j=2;j<=9;j++){
            b.g[tp(i,j)][tp(i,j-1)]=1;
        }
    }
    for(int i=1;i<=n;i++){
        scanf("%s",s+1);
        for(int j=1;j<=n;j++){
            int k=s[j]-'0';
            b.g[i][tp(j,k)]=1;
        }
    }
    printf("%d\n",solve(t,n));
    return 0;
}

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

posted @ 2018-02-03 14:19  luyouqi233  阅读(252)  评论(0编辑  收藏  举报