牛客OI赛制测试2 B路径数量 - 矩阵快速幂

题目描述

给出一个 n * n 的邻接矩阵A.

A是一个01矩阵 .

A[i][j]=1表示i号点和j号点之间有长度为1的边直接相连.

求出从 1 号点 到 n 号点长度为k的路径的数目.

输入描述:

第1行两个数n,k (20 ≤n ≤ 30,1 ≤ k ≤ 10)
第2行至第n+1行,为一个邻接矩阵

输出描述:

题目中所求的数目

示例1

输入

复制

4 2
0 1 1 0
1 0 0 1
1 0 0 1
0 1 1 0

输出

复制

2

说明

 

样例如图:

第一条路径:1-2-4

第二条路径:1-3-4

思路:

离散数学的公式,矩阵自乘k次,a[1][n]表示从1到n经过k条边的路径个数

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cmath>
#include<map>
#include<set>
#include<string>
#include<cstring>
using namespace std;
#define ll long long
#define lson l,m,k<<1
#define rson m+1,r,k<<1|1
const int N=40;
ll b[N];
int n;
struct Matrix{
    ll a[N][N];
    void init(){
        memset(a,0,sizeof(a));
        for(int i=1;i<=N;i++){
            a[i][i]=1;
        }
    }
};
Matrix ans;

Matrix mul(Matrix a,Matrix b){
    Matrix c;
    memset(c.a,0,sizeof(c.a));
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            c.a[i][j]=0;
            for(int k=1;k<=n;k++){
                c.a[i][j]+=a.a[i][k]*b.a[k][j];
            }
        }
    }
    return c;
}

Matrix pow(Matrix a,int k){
    ans.init();
    while(k){
        if(k&1)ans=mul(ans,a);
        a=mul(a,a);
        k>>=1;
    }
    return ans;
}

int main(){
    int m;
    scanf("%d%d",&n,&m);
    Matrix b;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            scanf("%lld",&b.a[i][j]);
        }
    }
    b=pow(b,m);
    printf("%lld\n",b.a[1][n]);
}

猜你喜欢

转载自blog.csdn.net/m0_37579232/article/details/82588303