HDU - 2157 - 邻接矩阵k条路定理 - 矩阵快速幂

传送门
离散书里有一个定理,从一个点到另一个点走k条路的方案数,求出邻接矩阵的k次方,最后邻接矩阵的答案就是方案数。
题目说的有问题。
在给定的有向图里,可能存在一个点到另一个点存在多条道路,但是只能算一次。

#include <iostream>
#include <cstdio>
#include <cstring>
#define ll long long
using namespace std;
const int N = 23;
const int mod = 1000;
struct Matrix{
    int n, m;
    ll a[N][N];
    Matrix (int n = 0, int m = 0) : n(n),m(m){memset(a, 0, sizeof(a));}
    Matrix operator * (const Matrix &b) const {
        Matrix ans(n, b.m);
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < b.m; j++) {
                for(int k = 0; k < m; k++) {
                    ans.a[i][j] = (ans.a[i][j] + a[i][k] * b.a[k][j] % mod) % mod;
                }
            }
        }
        return ans;
    }
};
Matrix ksm(Matrix a, ll b){
    Matrix ans(a.n, a.m);
    for(int i = 0; i < max(a.n, a.m); i++) ans.a[i][i] = 1;
    while(b) {
        if(b & 1) ans = ans * a;
        a = a * a;
        b >>= 1;
    }
    return ans;
}
ll a[N][N];
int n, m;
void solve(int aa, int bb, int k){
    Matrix base(n, n);
    for(int i = 0; i < n; i++)
        for(int j = 0; j < n; j++) 
            base.a[i][j] = a[i][j];
    base = ksm(base, k);
    printf("%lld\n", base.a[aa][bb]);
}
int main(){
    while(~scanf("%d%d", &n, &m)){
        if(n == 0 && m == 0) break;
        memset(a, 0, sizeof(a));
        for(int i = 1; i <= m; i++) {
            int u, v;
            scanf("%d%d", &u, &v);
            a[u][v] = 1;
        }
        int t; scanf("%d", &t);
        while(t--) {
            int a, b, k;
            scanf("%d%d%d", &a, &b, &k);
            solve(a, b, k);
        }
    }
    return 0;
}
posted @ 2020-10-12 14:03  Emcikem  阅读(202)  评论(0编辑  收藏  举报