题意
给出一个有向图,其中每条边的边长都为1。求这个图中长度恰为 $k$ 的路劲的总数。($1 leq n leq 100, 1 leq kleq 10^9$)
分析
首先,$k=1$ 时答案就等于边数。
当 $k=2$,$G_2[i][j] = sum_{w=1}^nG_1[i][w] imes G_1[w][j]$,相当于选取一个中间节点 $w$,只要存在合适的 $w$ ,$u,v$ 之间就存在通路。
以此类推,$G_k = G^k$ 表示恰好走 $k$ 步的情况,只需统计其中非零元素的个数。
这个算法的复杂度为 $O(n^3logn)$.
如果是求 $k$ 步之内的路径数,只需将每种情况累加,即 $S = A+A^2+...+A^k$,这个复杂度也能做到 $O(n^3 log n)$.
#include<cstdio> #include<cstring> using namespace std; typedef long long ll; struct matrix { int r, c; int mat[105][105]; matrix(){ memset(mat, 0, sizeof(mat)); } }; int n, m, k; matrix mul(matrix A, matrix B) //矩阵相乘 { matrix ret; ret.r = A.r; ret.c = B.c; for(int i = 0;i < A.r;i++) for(int k = 0;k < A.c;k++) for(int j = 0;j < B.c;j++) { ret.mat[i][j] = (ret.mat[i][j] + A.mat[i][k] * B.mat[k][j]) > 0 ? 1 : 0; //只要区分0和非0即可 } return ret; } matrix mpow(matrix A, int n) { matrix ret; ret.r = A.r; ret.c = A.c; for(int i = 0;i < ret.r;i++) ret.mat[i][i] = 1; while(n) { if(n & 1) ret = mul(ret, A); A = mul(A, A); n >>= 1; } return ret; } int main() { scanf("%d%d%d", &n, &m, &k); matrix A; A.r = A.c = n; for(int i = 0;i < m;i++) { int u, v; scanf("%d%d", &u, &v); A.mat[u-1][v-1] = 1; } A = mpow(A, k); int ans = 0; for(int i = 0;i < n;i++) for(int j = 0;j < n;j++) ans += A.mat[i][j]; printf("%d ", ans); return 0; }