HDU 5607 graph(矩阵优化+概率DP)

该题很容易想到求概率的转移方程:用d[i][j]表示第i步,走到j点的概率。

但是该题的k高达1e9,所以按照套路,要用矩阵相乘来优化。

第一次写矩阵相乘, 大概的意思就是利用矩阵实现递推, 并且因为每次递推的过程一样, 所以就相当于右乘这个矩阵的k次方。 用矩阵快速幂即可。

矩阵相乘这个问题, 大概可以看成, 矩阵中的每个元素表示到该点的概率, 那么另一个矩阵就是DP矩阵, 表示当前一步到各点的概率, 矩阵相乘就等于下一步到各点的概率(矩阵乘法的意义)。

另外, 要对答案进行1e9+5次方再取模, 如果最后取模, 那么将对分母Y进行取模后再次方再取模, 这是和原问题不等价的, 所以解决方法是按照乘法取模公式, 先对矩阵元素提前处理该操作。

细节参见代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef long long ll;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int INF = 1000000000;
const int mod = 1000000000 + 7;
const int maxn = 1000 + 10;
ll T,n,q,u,k,m,x,y,cnt[maxn];
vector<ll> g[maxn];
typedef vector<ll> vec;
typedef vector<vec> mat;
mat mul(mat &a, mat &b) {
    mat c(a.size(), vec(a.size()));
    for(int i=1;i<=n;i++) {
        for(int k=1;k<=n;k++) {
            for(int j=1;j<=n;j++) {
                c[i][j] = (c[i][j] + a[i][k] * b[k][j]) % mod;
            }
        }
    }
    return c;
}
mat pow(mat a, ll k) {
    mat b(a.size(), vec(a.size()));
    for(int i=1;i<=n;i++) {
        b[i][i] = 1;
    }
    while(k > 0) {
        if(k & 1) b = mul(b, a);
        a = mul(a, a);

        k >>= 1;
    }
    return b;
}
ll mod_pow(ll x, ll n, ll mod) {
    ll res = 1;
    while(n > 0) {
        if(n & 1) res = res * x % mod;
        x = x * x % mod;
        n >>= 1;
    }
    return res;
}
int main() {
    while(~scanf("%I64d%I64d",&n,&m)) {
        for(int i=1;i<=n;i++) g[i].clear();
        memset(cnt, 0, sizeof(cnt));
        mat a(n+3, vec(n+3));
        for(int i=0;i<m;i++) {
            scanf("%I64d%I64d",&x,&y);
            g[y].push_back(x);
            a[y][x] = 1;
            cnt[x]++;
        }
        for(int i=1;i<=n;i++) {
            cnt[i] = mod_pow(cnt[i], 1000000005, mod);
        }
        for(int i=1;i<=n;i++) {
            int len = g[i].size();
            for(int k=0;k<len;k++) {
                a[i][g[i][k]] = (a[i][g[i][k]] * cnt[g[i][k]]) % mod;
            }
        }
        scanf("%I64d",&q);
        while(q--) {
            scanf("%I64d%I64d",&u,&k);

            mat hehe = pow(a, k);
            for(int i=1;i<=n;i++) {
                printf("%I64d ", hehe[i][u]);
            }
            printf("\n");
        }
    }
    return 0;
}





你可能感兴趣的:(dp,HDU,矩阵快速幂)