[HDU2157]How many ways??(DP + 矩陣優化)
阿新 • • 發佈:2017-09-07
per printf 需要 給定 get sizeof ref 傳送門 href
傳送門
k < 20
k這麽小,隨便dp一下就好了。。。
dp[i][j][k]表示從i到j經過k個點的方案數
4重循環。。
但是如果k很大就不好弄了
把給定的圖轉為鄰接矩陣,即A(i,j)=1當且僅當存在一條邊i->j。令C=A*A,那麽C(i,j)=ΣA(i,k)*A(k,j),實際上就等於從點i到點j恰好經過1個點的路徑數(枚舉k為中轉點)。類似地,C*A的第i行第j列就表示從i到j經過2個點的路徑數。同理,如果要求經過k步的路徑數,我們只需要二分求出A^k即可。
#include <cstdio> #include <cstring> #define p 1000 int n, m, k, T; struct Matrix { int n, m; int a[21][21]; Matrix() { n = m = 0; memset(a, 0, sizeof(a)); } }ans; inline Matrix operator * (Matrix x, Matrix y) { int i, j, k; Matrix ans; ans.n = x.n; ans.m = y.m; for(i = 1; i <= x.n; i++) for(j = 1; j <= y.m; j++) for(k = 1; k <= y.n; k++) ans.a[i][j] = (ans.a[i][j] + x.a[i][k] * y.a[k][j]) % p; return ans; } inline Matrix operator ^ (Matrix x, int y) { int i; Matrix ans; ans.n = ans.m = n; for(i = 1; i <= n; i++) ans.a[i][i] = 1; for(; y; y >>= 1) { if(y & 1) ans = x * ans; x = x * x; } return ans; } int main() { int i, x, y; while(~scanf("%d %d", &n, &m) && n + m) { Matrix c; c.n = c.m = n; for(i = 1; i <= m; i++) { scanf("%d %d", &x, &y); c.a[x + 1][y + 1] = 1; } scanf("%d", &T); for(i = 1; i <= T; i++) { scanf("%d %d %d", &x, &y, &k); ans = c ^ k; printf("%d\n", ans.a[x + 1][y + 1]); } } return 0; }
[HDU2157]How many ways??(DP + 矩陣優化)