bzoj1297 [SCOI2009]迷路——拆点+矩阵快速幂

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1297

一看感觉是矩阵快速幂之类的,但边权不好处理啊;

普通的矩阵快速幂只能处理边权为1的,所以想办法把边权处理成1;

仔细一看还有一个条件是边权小于10;

所以拆点!把一个点拆成10个点表示到它不同的距离,那么和它相连的那些点就可以跟某个距离的点连边权为1的边;

虽然没有自己想出来,不过1A还是极好的!(因为太简单了)

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,T,w[15][15],tot,id[15][15],mod=2009;
struct Matrix{
    int a[105][105];
    Matrix(){memset(a,0,sizeof a);}
    Matrix operator * (const Matrix &y) const
    {
        Matrix x;
        for(int i=1;i<=tot;i++)
            for(int k=1;k<=tot;k++)
                for(int j=1;j<=tot;j++)
                    (x.a[i][j]+=a[i][k]*y.a[k][j])%=mod;
        return x;
    }
    void init(){for(int i=1;i<=tot;i++)a[i][i]=1;}
}f,ans;
Matrix pw(Matrix x,int k)
{
    Matrix ret; ret.init();
    for(;k;k>>=1,x=x*x)
        if(k&1)ret=ret*x;
    return ret;
}
int main()
{
    scanf("%d%d",&n,&T);
    char ch[15];
    for(int i=0;i<n;i++)
    {
        scanf("%s",&ch);
        for(int j=0;j<n;j++)
            w[i][j]=ch[j]-'0';
    }
    for(int i=0;i<n;i++)
        for(int j=0;j<=9;j++)
        {
            id[i][j]=++tot;
            if(j)f.a[tot-1][tot]++;
        }
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            if(w[i][j])f.a[id[i][w[i][j]-1]][id[j][0]]++;
    ans.a[1][id[0][0]]=1;
    Matrix fn=pw(f,T);
    ans=ans*fn;
    printf("%d",ans.a[1][id[n-1][0]]);
    return 0;
}

 

posted @ 2018-07-02 16:55  Zinn  阅读(140)  评论(0编辑  收藏  举报