hdu2157How many ways?? 矩阵快速幂

//给定一个有向图,问从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即可
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std ;
const int maxn = 110 ;
const int mod = 1000  ;
int a[maxn][maxn] ;
int c[maxn][maxn] ;
int tmp[maxn][maxn] ;
int temp[maxn][maxn] ;
void pow(int k , int n)
{
   memset(c ,0 , sizeof(c)) ;
   for(int i = 1;i <= n;i++)
   c[i][i] = 1 ;
   while(k)
   {
       if(k&1)
       {
           memcpy(tmp , c , sizeof(tmp)) ;
           memset(c , 0 ,sizeof(c)) ;
           for(int i = 1;i <= n;i++)
             for(int j = 1;j <= n;j++)
               for(int k = 1;k <= n;k++)
               c[i][j] = (c[i][j] + a[i][k]*tmp[k][j])%mod ;
       }
       memcpy(tmp , a, sizeof(a)) ;
       memset(a , 0  ,sizeof(a)) ;
       for(int i = 1;i <= n;i++)
         for(int j = 1;j <= n;j++)
           for(int k = 1;k <= n;k++)
           a[i][j] = (a[i][j] + tmp[i][k]*tmp[k][j])%mod ;
        k >>= 1 ;
   }
}
int main()
{
    //freopen("in.txt" , "r" , stdin) ;
    int n  , m ;
    while(scanf("%d%d" , &n  ,&m)&&(n+m))
    {
        memset(a , 0  ,sizeof(a)) ;
        while(m--)
        {
            int u , v ;
            scanf("%d%d" , &u , &v) ;
            a[u+1][v+1] = 1 ;
        }
        int t ;
        memcpy(temp , a , sizeof(a)) ;
        scanf("%d" , &t) ;
        while(t--)
        {
            memcpy(a , temp , sizeof(temp)) ;
            int u , v , k ;
            scanf("%d%d%d" , &u , &v ,&k) ;
            pow(k , n) ;
            cout<<c[u+1][v+1]<<endl ;
        }
    }
    return 0 ;
}


你可能感兴趣的:(hdu2157How many ways?? 矩阵快速幂)