邻接矩阵 矩阵快速幂(1504骑士游历)

HihoCoder-1504 骑士游历

思路:

       此类搜索一般dfs。但是这里的数据量太大,显然会造成树很深,所以不便于深搜的展开。从(R,C)走N步都多少种走法,可以理解为从(R,C)走N步到(1,1)-(8,8)走法的和,显然运用到了离散数学中邻接矩阵的知识。_map[i][j]=x表示从i结点到j结点走一步可到达有x种方法,_map[i][j]^n=x表示走n步有x种方法可以从i走到j。(具体了解离散数学,再次简述,假设矩阵相乘_map[i][j]^m _map[i][j]^n,那么对于_map[1][2]^(m+n)时由_map[1][k]*_map[k][2]逐个相加,可以这样理解,_map[1][k]表示从1走到k有x种方法,_map[k][2]表示从k走到2有y种方法,那么经过k结点从1到2就有x*y种方法,遍历每一个点当中间结点,那么最后也就是矩阵相乘的结果).

邻接矩阵:

       _map[i][j]表示从第i个点到第j个点可不可到,(1,1)-(8,8)逐个编号0-63;

知识点:

1.矩阵乘法代码实现。

       2.快速幂的矩阵用法。

       3.取模注意事项,只要牵扯四则运算 就取模。

       4.函数返回二维数组指针较复杂,可以用结构体封装起来返回结构体,较为简单。

代码实现:

#include<algorithm>

#include<iostream>

#include<cstring>

#include<cstdio>

#include<cmath>

#include<stdlib.h>



using namespace std;

typedef long long ll;

const int INF = 0x3f3f3f3f;

const int mod = 1000000007; //需要的取模大小

int dir[8][2] = {{1,2},{2,1},{-1,2},{1,-2},{2,-1},{-2,1},{-1,-2},{-2,-1}};//用于初始化矩阵可以到达的位置。

typedef struct {//封装矩阵

       ll _map[100][100];

}mat;

ll r,c;

mat init(mat a){//初始化邻接矩阵

       for(int i = 0;i < 8;i++){

              for(int j = 0;j < 8;j++){

                     for(int k = 0;k < 8;k++){

                            int tx = i+dir[k][0];

                            int ty = j+dir[k][1];

                            if(tx < 0||ty < 0||tx >= 8||ty >= 8) continue;

                            a._map[i*8+j][tx*8+ty] = 1;

                     }

              }

       }

       return a;

}

mat mul(mat a,mat b){

       mat c;

       memset(c._map,0,sizeof(c._map));

       for(int i = 0;i < 64;i++){

              for(int j = 0;j < 64;j++){

                     for(int k = 0;k < 64;k++){

                            c._map[i][j] += (a._map[i][k]*b._map[k][j])%mod;

                            c._map[i][j]%=mod;//注意此处取模,上面未对c取模

                     }

              }

       }

       return c;

}

void qpow(mat a,ll n){

       mat ans;

       memset(ans._map,0,sizeof(ans._map));

       for(int i = 0;i < 64;i++)//注意:普通快速幂ans=1,在矩阵中初始化为单位阵(即矩阵的单位元)

              ans._map[i][i] = 1;

       while(n){

              if(n % 2 == 1) {

                     ans = mul(ans,a);

              }

              a = mul(a,a);

              n/=2;

       }

       int s = (r-1)*8+(c-1);//因为我们矩阵从0开始的,所以需要减一(题目中从1开始)

       int ans1 = 0;

       for(int i = 0;i < 64;i++){//遍历每一个点,看从(R,C)到该点有多少种路径

              ans1 = (ans1+ans._map[s][i])%mod;

       }

       cout << ans1 << endl;

}

int main(){

       mat m;

       ll n;

       m = init(m);

       cin >> n >> r >> c;

       qpow(m,n);

       return 0;

}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值