矩阵乘法 经典题目

本文探讨了利用矩阵快速幂算法高效求解图论中的路径计数问题及组合问题中的多米诺骨牌填充方案。通过矩阵运算,文章详细解释了如何将图的邻接矩阵进行幂次方运算来计算两点间特定步数的路径数量,并提供了一个具体实例,展示如何使用矩阵快速幂算法计算在MxN矩形中使用1x2多米诺骨牌填充的所有可能方案。
摘要由CSDN通过智能技术生成

1。  给定一个有向图,问从A点恰好走k步(允许重复经过边)到达B点的方案数mod p的值  

把给定的图转为邻接矩阵,即A(i,j)=1当且仅当存在一条边i->j。令C=A*A,那么C(i,j)=ΣA(i,k)*A(k,j),实际上就等于从点i到点j恰好经过2条边的路径数(枚举k为中转点)。类似地,C*A的第i行第j列就表示从i到j经过3条边的路径数。同理,如果要求经过k步的路径数,我们只需要二分求出A^k即可。

--摘自,http://www.matrix67.com/blog/archives/276/

理解:

为什么k步的路径数,我们只需要二分求出A^k?

因为每步实际做一次矩阵乘法,矩阵乘法定义就是C(i,j)=ΣA(i,k)*A(k,j)。

2.经典题目9 用1 x 2的多米诺骨牌填满M x N的矩形有多少种方案,M<=5,N<2^31,输出答案mod p的结果

 

View Code
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<iostream>
#include<vector>
#include<string>
#include<math.h>
#include<map>
#include<set>
#include<algorithm>
using namespace std;

#define MAXN 258
#define MOD 9937
#define size (1<<M)
int N, M;
int ans[1200];


class Matrix
{
  public:
    int mt[MAXN][MAXN];
    Matrix  Multiply(Matrix);
    Matrix  Add(Matrix);
    Matrix  quickpower(int);
}AA;



Matrix Matrix::Add(Matrix A)
{
   Matrix C;
   for( int i = 1; i <= size; i++)
     for( int j = 1; j <= size; j++)
         C.mt[i][j] = mt[i][j] + A.mt[i][j];                     
   return C;
}

Matrix Matrix::Multiply(Matrix A)
{
   Matrix C;
   for( int i = 0; i < size; i++)
   {
       for( int j = 0; j < size; j++)
       {
            
            int sum = 0;
            for( int k = 0; k < size; k++)
            {
              if( A.mt[i][k] && mt[k][j] )
              {    
               sum += (A.mt[i][k] % MOD) * (mt[k][j] % MOD);
               sum %= MOD;
               }
                 
            }     
            C.mt[i][j] = sum;
            
       }     
        
        
   }
   return C;     
}

Matrix Matrix::quickpower(int n)
{
  Matrix B;
  B = *this;
  while( n > 0 )
  {
     if( n & 1 )
         *this = (*this).Multiply(B);
     n = n / 2;
     B = B.Multiply(B);             
  }
  return *this;
}

//横的摆放状态 
void pre(int x, int state)
{
  if( x > M )
      return;
  if( x == M )
  {
    ans[state] = 1;
    return;
  }
  pre(x + 1, state << 1 );
  pre(x + 2, 3 | (state << 2) ); 
}

int main( )
{
  while( scanf("%d%d",&N,&M) != EOF )
  {
    if( N < M )
        swap(N,M);
    memset(ans, 0, sizeof(ans));
    pre(0, 0);
    if( N % 2 == 1 && M % 2 == 1 )
    {
       puts("0"); continue;
    }
    for( int i = 0; i < (1<<M); i++)
    {
        for( int j = 0; j < (1<<M); j++)
        {   
            AA.mt[i][j] = 0;
            if( ((~i)&j) == ((~i)&((1<<M)-1)) )
            {
                 AA.mt[i][j] = ans[i&j];     
            }     
        }     
    }
    AA = AA.quickpower(N-1);
    printf("%d\n",AA.mt[(1<<M)-1][(1<<M)-1]);       
  }  
  return 0;
}

 

 

 

 

 

转载于:https://www.cnblogs.com/tangcong/archive/2012/08/17/2643747.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值