HDU 2157 How many ways??:矩阵快速幂【i到j共经过k个节点的方法数】
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2157
题解:
给你一个有向图,n个节点m条边,问你从i到j共经过k个节点的方法数(不算i点)。
题解:
先用邻接矩阵存图。
假设k = 2,那么从i到j的方法数 = ∑ way[i][x] * way[x][j] (0<=x<n && x!=i && x!=j)
诶?快看,那是矩阵乘法!
设邻接矩阵为A,若i到j有边则val[i][j] = 1。
k = 2时答案矩阵ans是A^2,答案就是ans.val[i][j]。
那k任意时,答案矩阵就是A^k,答案为ans.val[i][j]。
AC Code:
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #define MAX_L 25 5 #define MOD 1000 6 7 using namespace std; 8 9 struct Mat 10 { 11 int n; 12 int m; 13 int val[MAX_L][MAX_L]; 14 Mat() 15 { 16 n=0; 17 m=0; 18 memset(val,0,sizeof(val)); 19 } 20 }; 21 22 int n,m,t; 23 int a,b,k; 24 25 Mat make_unit(int n) 26 { 27 Mat mat; 28 mat.n=n; 29 mat.m=n; 30 for(int i=0;i<n;i++) 31 { 32 mat.val[i][i]=1; 33 } 34 return mat; 35 } 36 37 Mat mul_mat(const Mat &a,const Mat &b) 38 { 39 Mat c; 40 if(a.m!=b.n) 41 { 42 cout<<"Error: mul_mat"<<endl; 43 return c; 44 } 45 c.n=a.n; 46 c.m=b.m; 47 for(int i=0;i<a.n;i++) 48 { 49 for(int j=0;j<b.m;j++) 50 { 51 for(int k=0;k<a.m;k++) 52 { 53 c.val[i][j]+=a.val[i][k]*b.val[k][j]; 54 c.val[i][j]%=MOD; 55 } 56 } 57 } 58 return c; 59 } 60 61 Mat quick_pow_mat(Mat mat,int k) 62 { 63 Mat ans; 64 if(mat.n!=mat.m) 65 { 66 cout<<"Error: quick_pow_mat"<<endl; 67 return ans; 68 } 69 ans=make_unit(mat.n); 70 while(k) 71 { 72 if(k&1) 73 { 74 ans=mul_mat(ans,mat); 75 } 76 mat=mul_mat(mat,mat); 77 k>>=1; 78 } 79 return ans; 80 } 81 82 int main() 83 { 84 while(cin>>n>>m) 85 { 86 if(n==0 && m==0) break; 87 Mat start; 88 start.n=n; 89 start.m=n; 90 for(int i=0;i<m;i++) 91 { 92 cin>>a>>b; 93 start.val[a][b]=1; 94 } 95 cin>>t; 96 for(int i=0;i<t;i++) 97 { 98 cin>>a>>b>>k; 99 Mat ans=quick_pow_mat(start,k); 100 cout<<ans.val[a][b]<<endl; 101 } 102 } 103 }