bzoj1297: [SCOI2009]迷路

矩阵。

一个图的邻接矩阵的m次幂相当于 长度恰好为m的路径数。这要求边权为1。

因为边权小于等于9,所以可以把一个点拆成9的点。 拆成的第(i+1)个点向第i个点连边。

如果存在边(u,v,w) 就由u点向v拆成的第w个点连边,这样表明w次以后就可以到达v点。

这个拆点很牛啊,不过第一眼连邻接矩阵都没看出来。。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 100 + 10;
const int mod = 2009; 

struct Matrix {
    int a[maxn][maxn];
    int n;
    
    int* operator [] (int x) {
        return a[x];    
    }
    
    Matrix operator* (Matrix b) {
        Matrix c;
        c.n=n;
        for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        for(int k=1;k<=n;k++)
            c[i][k]=(c[i][k]+a[i][j]*b[j][k])%mod;    
        return c;
    }
    
    Matrix operator^ (int e) {
        Matrix res,tmp=*this;
        res.init(n);
        while(e) {
            if(e&1) res=res*tmp;
            tmp=tmp*tmp;
            e>>=1;    
        }
        return res;
    }
    
    void output() {
        for(int i=1;i<=n;i++) {            
            for(int j=1;j<=n;j++)
                printf("%d ",a[i][j]);
            printf("\n");        
        }
    }
    
    void input() {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++) 
            scanf("%d",&a[i][j]);
    }
    
    void init(int k) {
        n=k;
        for(int i=1;i<=n;i++) a[i][i]=1;    
    }
    
    Matrix() {
        memset(a,0,sizeof(a));    
    }
}g,res;

int n,m,k,vid;
int id[maxn][maxn];

int main() {
    scanf("%d%d",&n,&m); 
    k=n*9; res.n=g.n=k; 
    for(int i=1;i<=n;i++)
    for(int j=1;j<=9;j++) 
        id[i][j]=++vid;
    
    for(int i=1;i<=n;i++)
    for(int j=1;j<9;j++)
        g[id[i][j+1]][id[i][j]]=1;
    
    
    for(int i=1,t;i<=n;i++)
    for(int j=1;j<=n;j++) {
        scanf("%1d",&t);
        if(!t) continue;
        g[id[i][1]][id[j][t]]=1;
    }    
    for(int i=1;i<=k;i++) res[i][i]=1;
    res=res*(g^m);
    printf("%d\n",res[id[1][1]][id[n][1]]);
    return 0;    
}
posted @ 2016-07-02 10:38  invoid  阅读(343)  评论(0编辑  收藏  举报