HDU2157(矩陣的一種 經典問題)
阿新 • • 發佈:2018-11-06
給定一個有向圖,問從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即可。
刷AC自動機的時候用到這種思想了才刷的這道題.
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<string> #include<string> #include<vector> #include<queue> #include<stack> #include<cmath> #include<set> #include<map> using namespace std; #define rep(i,aa,n) for (int i=aa;i<n;i++) #define per(i,a,n) for (int i=n-1;i>=a;i--) #define oo cout<<"!!!"<<endl; typedef long long ll; typedef unsigned long long ull; #define ms(s) memset(s, 0, sizeof(s)) const int inf = 0x3f3f3f3f; //head //HDU 2157.離散數學裡的一個結論.AC自動機那幾道題的解法來源於這道題 const int maxn = 111; const int mod = 1000; struct matrix { int m[maxn][maxn]; }; matrix mul(matrix a,matrix b,int sz) { matrix c; rep(i,0,sz) rep(j,0,sz) { c.m[i][j] = 0; rep(k,0,sz) c.m[i][j] = (c.m[i][j] + a.m[i][k]*b.m[k][j]) % mod; } return c; } matrix pow(matrix a,int n,int sz) { matrix res; rep(i,0,sz) rep(j,0,sz) res.m[i][j] = i==j; while(n) { if(n & 1)res = mul(a,res,sz); a = mul(a,a,sz); n >>= 1; } return res; } int main() { int n,m,q; while(cin>>n>>m,n||m) { int x,y; matrix mat; ms(mat.m); rep(i,0,m) cin>>x>>y,mat.m[x][y]=1; cin>>q; int a,b,k; while(q--) { cin>>a>>b>>k; matrix ans = pow(mat,k,n); cout<<ans.m[a][b]<<endl; } } return 0; }