关于有向图走“无限次”后求概率/期望的口胡/【题解】HNCPC2019H 有向图

关于有向图走“无限次”后求概率/期望的口胡/【题解】HNCPC2019H 有向图

全是口胡 假了不管

讨论的都是图\(G=(V,E),|V|=n,|E|=m\)上的情况

“走无限次”这个概念很抽象,严谨的证明以及描述和概率的收敛性有关,由于我也不会在此就不讨论这些,但是根据一些概率的知识,可以发现,其实走无限次可以这样描述:

由于使用概率不好描述在无限次的情况时,每个点和点之间的关系,所以用期望。到时候根据期望的定义式反过来求概率。可能的问题是,“不是走无限次吗,那怎么用期望反过来求概率?”。举个例子,假若只有一个起点且存在那些游戏黑洞(过去了走不来),那么所有随机变量\(X=1\),所以\(E(X)=XP(X)=P(X)\)

这是因为期望可以很方便的描述点与点之间的关系(用概率的话,不好描述走无限次的“过程”,在从0次走到无穷次的途中的关系不好用概率描述(因为概率是一个相乘的关系,而期望是相乘且求和(概率不也是吗?我也不知道我在说什么,可能这段话是强行解释,因为我做的题都是用这个得到初始条件的)))

\(e=[f_i\dots]\)\(i\)点的期望构成的行向量,至于我们如何定义“i点的期望”,具体问题具体分析。

设矩阵\(A_{n\times n}\)是“增广矩阵”(我xjb取的名字),其中\(A_{i,j}\)表示由\(i\)点转移到\(j\)点的概率(到底如何定义具体情况具体分析,这里是笼统的口胡),那么走无限次可以这样描述:
\[ e\times A=e \]

然后对比\(f_i\)系数,
可以得到\(n\)个方程。但是这\(n\)个是解出不来值的(全是 \(f_i=0\)),为什么?

这是因为忽略了初始条件,很显然\(e\times A=e\)有且只有一个解就是\(e= 0(A\not = O)\) ,必须要根据\(f_i\)的定义加入初始条件才行(比如\(f_i\)+=c之类的)。从这里我们可以知道,\(f_i\)的含义要方便我们加入初始条件。

由这\(n\)的个方程可以最坏\(O(n^3)\)解出来所有\(f_i\)。在\(A\)矩阵不同的特征或者性质下,可能有别的方法求解\(f_i\)

口胡好爽...

扫描二维码关注公众号,回复: 7845466 查看本文章

接下来是具体问题具体分析的例子

【题解】HNCPC2019H 有向图

有向图

“照本宣科”,设\(f_i\)是经过\(i\)点的期望次数,概率矩阵基本上已经告诉我们了,那么我们直接解就行了。

然而值得注意的是,由于这个概率矩阵的特性,可以得到\(f_i,i\le n\)的解,然后再求剩下的那些期望。

方程是
\[ f_i= \begin{cases} \sum_\limits{j} A_{j,i}f_j+1 &(n=1) \\ \sum_\limits{j} A_{j,i}f_j &(n>1) \end{cases} \]
高斯消元

//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define DEBUG(s) cerr<<(#s)<<" = "<<(s)<<endl

using namespace std;  typedef long long ll; 
inline int qr(){
    register int ret=0,f=0;
    register char c=getchar();
    while(!isdigit(c))f|=c==45,c=getchar();
    while(isdigit(c)) ret=ret*10+c-48,c=getchar();
    return f?-ret:ret;
}
const int mod=1e9+7;

inline int ksm(const int&ba,const int&p){
    int ret=1;
    for(int t=p,b=ba;t;t>>=1,b=1ll*b*b%mod)
        if(t&1) ret=1ll*ret*b%mod;
    return ret;
}
inline int inv(const int&x){return ksm(x,mod-2);}

const int maxn=505;
int n,m;
struct MAT{
    int data[maxn];
    MAT(){memset(data,0,sizeof data);}
    inline int&operator[](int x){return data[x];}
    inline MAT operator *(const int&x){
        MAT ret;
        for(int t=1;t<=n+1;++t) ret[t]=1ll*data[t]*x%mod;
        return ret;
    }
    inline MAT operator *=(const int&x){return *this=*this*x;}
    inline MAT operator -(const MAT&a){
        MAT ret;
        for(int t=1;t<=n+1;++t) ret[t]=(data[t]-a.data[t]+mod)%mod;
        return ret;
    }
    inline MAT operator -=(const MAT&a){return *this=*this-a;}
    inline void print(){
        for(int t=1;t<=n+1;++t) printf("%d ",data[t]);
        putchar('\n');
    }
}e[maxn];
int p[maxn][maxn<<1];

inline void Solve(){
    for(int t=1;t<=n;++t){
        e[t]*=inv(e[t][t]);
        for(int i=1;i<=n;++i)
            if(i^t) e[i]-=(e[t]*e[i][t]);
    }
}

int main(){
    while(~scanf("%d%d",&n,&m)){
        memset(e,0,sizeof e);
        memset(p,0,sizeof p);
        for(int t=1,in=inv(10000);t<=n;++t)
            for(int i=1;i<=m+n;++i)
                p[t][i]=1ll*qr()*in%mod;
        for(int t=1;t<=n;++t){
            for(int i=1;i<=n;++i) e[t][i]=p[i][t];
            e[t][t]=(e[t][t]-1+mod)%mod;
        }
        e[1][n+1]=mod-1;
        Solve();
        for(int t=1;t<=m;++t){
            int ans=0;
            for(int i=1;i<=n;++i) ans=(ans+1ll*e[i][n+1]*p[i][t+n])%mod;
            printf("%d ",ans);
        }
        putchar('\n');
    }
    return 0;
}


猜你喜欢

转载自www.cnblogs.com/winlere/p/11852977.html