zoukankan      html  css  js  c++  java
  • BZOJ 3270 博物馆 ——概率DP 高斯消元

    用$F(i,j)$表示A在i,B在j的概率。

    然后很容易列出转移方程。

    然后可以高斯消元了!

    被一个问题困扰了很久,为什么起始点的概率要加上1。

    (因为其他博客上都是直接写成-1,雾)

    考虑初始状态是由什么转移过来的,发现可以由其他点走过来,也可以由初始定义转移。

    而初始的定义就决定了它有一个1的概率。

    加上之后就可以高斯消元了

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    #define F(i,j,k) for (int i=j;i<=k;++i)
    #define D(i,j,k) for (int i=j;i>=k;--i)
    double a[405][405],p[21];
    int id[21][21],n,m,x,y,du[21],tot,st;
    int h[405],to[405],ne[405],en=0;
     
    void add(int a,int b)
    {
        to[en]=b;ne[en]=h[a];h[a]=en++;
    }
     
    void solve(int x,int y)
    {
        int num=id[x][y];
        a[num][num]=1.0;
        for (int i=h[x];i>=0;i=ne[i])
            for (int j=h[y];j>=0;j=ne[j])
            {
                int tx=to[i],ty=to[j]; if (tx==ty) continue;
                int tnum=id[tx][ty];
                if (tx==x&&ty==y) a[num][tnum]-=p[tx]*p[ty];
                else if (tx==x) a[num][tnum]-=p[tx]*(1-p[ty])/(du[ty]*1.0);
                else if (ty==y) a[num][tnum]-=p[ty]*(1-p[tx])/(du[tx]*1.0);
                else a[num][tnum]-=(1-p[tx])*(1-p[ty])/(du[tx]*1.0)/(du[ty]*1.0);
            }
    }
     
    void gauss()
    {
        F(i,1,tot)
        {
            int tmp=i;
            while (!a[tmp][i]&&tmp<=tot) tmp++;
            if (tmp>tot) continue;//自由元
            F(j,i,tot+1) swap(a[i][j],a[tmp][j]);
            F(j,1,tot) if (j!=i)
            {
                double t=a[j][i]/a[i][i];
                F(k,1,tot+1)
                    a[j][k]-=t*a[i][k];
            }
        }
    }
     
    int main()
    {
        memset(h,-1,sizeof h);
        scanf("%d%d%d%d",&n,&m,&x,&y);
        F(i,1,m)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            add(a,b);add(b,a);
            du[a]++;du[b]++;
        }
        F(i,1,n) add(i,i);
        F(i,1,n) F(j,1,n) id[i][j]=++tot;
        a[id[x][y]][tot+1]=1;
        F(i,1,n) scanf("%lf",&p[i]);
        F(i,1,n) F(j,1,n) solve(i,j);
        gauss();
        F(i,1,n)
        {
            int t=id[i][i];
            printf("%.6f ",a[t][tot+1]/a[t][t]);
        }
        printf("
    ");
    }
    

      我怎么还是不会写高斯消元?(⊙_⊙?)

        方法二:

        考虑初始向量S,转移矩阵A

        那么答案就是$ans=SI+SA+SA^2...$

        所以$ans=S(I-A)^{-1}$

        然后就有$ans[I-A]^{T}=S$

        高斯消元即可,或者求逆之后矩阵乘法

    #include <map>
    #include <ctime>
    #include <cmath>
    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    #define F(i,j,k) for (int i=j;i<=k;++i)
    #define D(i,j,k) for (int i=j;i>=k;--i)
    #define maxn 405
    double f[402][402],p[402],d[402][402];
    double ans[402],S[402]; 
    int ed,n,m,sa,sb,cnt;
    int id[21][21],du[maxn],h[maxn],to[maxn],ne[maxn],en=0;
    void add(int a,int b)
    {to[en]=b;ne[en]=h[a];h[a]=en++;}
     
    void Build()
    {
        ed=cnt;
        F(i,1,n) F(j,1,n)
        if (i!=j) F(k,1,n) F(l,1,n)
            f[id[i][j]][id[k][l]]-=d[i][k]*d[j][l];
        F(i,1,ed) F(j,1,i-1) swap(f[i][j],f[j][i]);
        F(i,1,ed) f[i][i]+=1;
        f[id[sa][sb]][ed+1]=1;
    }
     
    void Gauss()
    {
        F(i,1,ed)
        {
            int tmp=i;
            F(j,i+1,ed) if (f[j][i]>f[tmp][i]) tmp=j;
            if (tmp!=i) F(j,i,ed+1) swap(f[tmp][j],f[i][j]);
            F(j,i+1,ed)
            {
                double t=f[j][i]/f[i][i];
                F(k,i,ed+1) f[j][k]-=t*f[i][k];
            }
        }
        D(i,ed,1)
        {
            F(j,i+1,ed) f[i][ed+1]-=f[i][j]*ans[j],f[i][j]=0;
            ans[i]=f[i][ed+1]/f[i][i];
        }
    }
     
    int main()
    {
        memset(h,-1,sizeof h);
        scanf("%d%d%d%d",&n,&m,&sa,&sb);
        F(i,1,m)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            add(a,b);add(b,a);
            du[a]++;du[b]++;
        }
        F(i,1,n) scanf("%lf",&p[i]);
        F(i,1,n)
        {
            d[i][i]=p[i];
            for (int j=h[i];j>=0;j=ne[j])
                d[i][to[j]]+=(1-p[i])/du[i];
        }
        F(i,1,n) F(j,1,n) id[i][j]=++cnt;
        Build();
        Gauss();
        F(i,1,n) printf("%.6f ",ans[id[i][i]]);
    }
    

      

  • 相关阅读:
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    基于分布式锁解决定时任务重复问题
    基于Redis的Setnx实现分布式锁
    基于数据库悲观锁的分布式锁
    使用锁解决电商中的超卖
  • 原文地址:https://www.cnblogs.com/SfailSth/p/6613556.html
Copyright © 2011-2022 走看看