zoukankan      html  css  js  c++  java
  • HDU 5607 graph(矩阵优化+概率DP)

    该题非常easy想到求概率的转移方程:用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("
    ");
            }
        }
        return 0;
    }
    
    
    
    


  • 相关阅读:
    vc++6.0如何调试
    Visual C++单文档混合分割视图
    使用VC6.0实现窗口的任意分割张中庆
    用MFC创建通用窗体分割框架
    vc++6.0编译环境介绍(1、2)
    浅谈SDI单文档多视切换方法
    单文档多视图Formview切换源代码(此网还有许多其它多视图切换的源代码)
    VC单文档实现多视图的方法
    Visual C++(VC++6.0)编译器常用选项设置
    PowerTip of the DayRemoving Empty Things
  • 原文地址:https://www.cnblogs.com/zhchoutai/p/8448347.html
Copyright © 2011-2022 走看看