传送门:>Here<
题意:给出一张有向图,问从点A到点B恰好经过k个点(包括终点)的路径方案数
解题思路
一道矩阵乘法的好题!妙哉~
话说把矩阵乘法放在图上好神奇,那么跟矩阵唯一有关的就是邻接矩阵……
考虑邻接矩阵在这道题里的含义也就是从A到B经过1个点的方案数——能到达或不能到达。而当邻接矩阵自乘时,假设自乘一次得到矩阵B,则$b[i][j] = sumlimits_{}{}g[i][k]*g[k][j]$。因此k就作为了枚举的中介点,由于最后得到的项是累积的,所以自乘一次以后就得到了经过2个点的方案数。因此自乘k-1即能得到经过k个点的方案数。
此时,乘法的意义就成为了每一次累积$(i->k)的方案数 * (k->j)的方案数 (起点终点固定)$
Code
/*By DennyQi*/ #include <cstdio> #include <queue> #include <cstring> #include <algorithm> #define r read() #define Max(a,b) (((a)>(b)) ? (a) : (b)) #define Min(a,b) (((a)<(b)) ? (a) : (b)) using namespace std; typedef long long ll; const int MAXN = 10010; const int MAXM = 27010; const int INF = 1061109567; inline int read(){ int x = 0; int w = 1; register int c = getchar(); while(c ^ '-' && (c < '0' || c > '9')) c = getchar(); if(c == '-') w = -1, c = getchar(); while(c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar(); return x * w; } int N,M,K,Q,x,y,A,B; int g[30][30],a[30][30],b[30][30],ans[30][30][30]; inline void Init(){ memset(g, 0, sizeof(g)); } inline void Matrix_mul(){ memset(ans, 0, sizeof(ans)); for(int num = 0; num <= 20; ++num){ for(int i = 1; i <= N; ++i){ ans[num][i][i] = 1; } } for(int num = 1; num <= 20; ++num){ for(int i = 1; i <= N; ++i){ for(int j = 1; j <= N; ++j){ b[i][j] = 0; for(int k = 1; k <= N; ++k){ b[i][j] = (b[i][j] + ans[num-1][i][k] * g[k][j]) % 1000; } } } for(int i = 1; i <= N; ++i){ for(int j = 1; j <= N; ++j){ ans[num][i][j] = b[i][j]; } } } } int main(){ for(;;){ N = r, M = r; if(!N && !M) break; Init(); for(int i = 1; i <= M; ++i){ x = r+1, y = r+1; g[x][y] = 1; } Matrix_mul(); Q = r; while(Q--){ A = r, B = r, K = r; printf("%d ", ans[K][A+1][B+1] % 1000); } } return 0; }