zoukankan      html  css  js  c++  java
  • CF446D DZY Loves Games

    CF446D DZY Loves Games 

    高斯消元好题

    如果暴力地,令f[i][k]表示到i,有k条命的概率,就没法做了。

    转化题意

    生命取决于经过陷阱的个数

    把这个看成一步

    所以考虑从一个陷阱到另一个陷阱,不经过其他陷阱的概率p[i][j]

    当然1出发到其他陷阱的概率也要得到。

    然后相当于有一个新图,

    从1出发,走k-1步恰好到n的概率

    暴力方法:

    枚举一个出发点s,

    则$P_x=sum_{v&&v!=trap}P_v/deg_v+P(x is a start)$

    特别地,v是s也可以转移(虽然s可能是陷阱,但是是出发点)

    O(n^4)

    考虑优化

    其实所有的系数都是一样的。只是常数项不一样。即$P(x is a start)$不同。

    什么,你说对于某些s是trap,但是作为出发点可以转移这里不同的s条件不同?

    我们可以枚举s的出点v,直接把v作为出发点,概率是1/deg(s)

    所以,我们可以把常数项扔到等号后面,堆成长度为陷阱数量的向量。

    一起带着消即可。

    #include<bits/stdc++.h>
    #define numb (ch^'0')
    #define il inline
    #define reg register int
    using namespace std;
    typedef long long ll;
    template<class T>il void rd(T &x){
        x=0;char ch;bool fl=false;
        while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);
        (fl==true)&&(x=-x);
    }
    template<class T>il void prt(T a[],int st,int nd){
        for(reg i=st;i<=nd;++i) cout<<a[i]<<" ";cout<<endl;
    }
    namespace Miracle{
    const int N=605;
    int has[N],con[N][N];
    int du[N];
    int id[N],mem[N],num;
    double f[N][N];
    double p[N][N];
    
    int n,m,T;
    void guass(int typ,int c){
    //    cout<<" guass "<<endl;
    //    for(reg i=1;i<=n;++i){
    //        for(reg j=1;j<=n+c;++j){
    //            cout<<f[i][j]<<" ";
    //        }cout<<endl;
    //    }
        
        for(reg i=1;i<=n;++i){
            int id=i;
            for(reg j=i+1;j<=n;++j){
                if(fabs(f[j][i])>fabs(f[id][i])) id=j;
            }
            if(id!=i){
                for(reg j=i;j<=n+c;++j){
                    swap(f[i][j],f[id][j]);
                }
            }
            for(reg j=i+1;j<=n;++j){
                if(fabs(f[j][i])>0){
                    double lp=f[j][i]/f[i][i];
                    for(reg k=i;k<=n+c;++k){
                        f[j][k]-=f[i][k]*lp;
                    }
                }
            }
        }
        if(typ!=1){
            for(reg i=n;i>=1;--i){
                for(reg j=i+1;j<=n;++j){
                    if(fabs(f[i][j])>0){
                        for(reg k=n+1;k<=n+c;++k){
                            f[i][k]-=f[i][j]*p[k-n][j];
                        }
                    }
                }
                for(reg k=n+1;k<=n+c;++k){
                    p[k-n][i]=f[i][k]/f[i][i];
                }
            }
        }else{
    //        for(reg i=1;i<=n;++i){
    //        for(reg j=1;j<=n+c;++j){
    //            cout<<f[i][j]<<" ";
    //        }cout<<endl;
    //    }
            for(reg i=n;i>=1;--i){
                for(reg j=i+1;j<=n;++j){
                    if(fabs(f[i][j])>0){
                        f[i][n+1]-=f[i][j]*p[0][j];
                    }
                }
                p[0][i]=f[i][n+1]/f[i][i];
            }
        }
    }
    struct tr{
        double a[105][105];
        tr(){memset(a,0,sizeof a);}
        void init(){
            for(reg k=0;k<=num;++k){
                a[k][k]=1.00;
            }
        }
        tr friend operator *(const tr &a,const tr &b){
            tr c;
            for(reg k=0;k<=num;++k){
                for(reg i=0;i<=num;++i){
                    for(reg j=0;j<=num;++j){
                        c.a[i][j]+=a.a[i][k]*b.a[k][j];
                    }
                }
            }
            return c;
        }
    }S,B;
    tr qm(tr B,int y){
        tr ret;ret.init();
        while(y){
            if(y&1) ret=ret*B;
            B=B*B;
            y>>=1;
        }
        return ret;
    }
    
    int main(){
        rd(n);rd(m);rd(T);
        for(reg i=1;i<=n;++i){
            rd(has[i]);
            if(has[i]) mem[++num]=i,id[i]=num;
        }
        int x,y;
        for(reg i=1;i<=m;++i){
            rd(x);rd(y);
            ++du[x];++du[y];
            ++con[x][y];++con[y][x];
        }
        for(reg i=1;i<=n;++i){
            f[i][i]=1.000;
            for(reg j=1;j<=n;++j){
                if(j==i) continue;
                if(!has[j]&&con[i][j]){
                    f[i][j]=-(double)con[i][j]/du[j];
                }
            }
            if(i==1) f[i][n+1]=1.00;
        }
        guass(1,1);
        
    //    for(reg i=1;i<=num;++i){
    //        cout<<" memi "<<i<<" : "<<mem[i]<<" "<<p[0][mem[i]]<<endl;
    //    }
        
        memset(f,0,sizeof f);
        
        for(reg i=1;i<=n;++i){
            f[i][i]=1.000;
            for(reg j=1;j<=n;++j){
                if(j==i) continue;
                if(!has[j]&&con[i][j]){
                    f[i][j]=-(double)con[i][j]/du[j];
                }
            }
            for(reg j=1;j<=num;++j){
                if(mem[j]==i) continue;
                if(con[mem[j]][i]){
                    f[i][j+n]=(double)con[mem[j]][i]/du[mem[j]];
                }
            }
        }
        guass(233,num);
        for(reg j=1;j<=num;++j){
            B.a[0][j]=p[0][mem[j]];
        }
        for(reg i=1;i<=num;++i){
            for(reg j=1;j<=num;++j){
                B.a[i][j]=p[i][mem[j]];
            }
        }
        // B.a[num][num]=1.00;
        
        // for(reg i=0;i<=num;++i){
        //     for(reg j=0;j<=num;++j){
        //         cout<<B.a[i][j]<<" ";
        //     }cout<<endl;
        // }
    
        S.a[0][0]=1.00;
        S=S*qm(B,T-1);
        
        printf("%.10lf",S.a[0][num]);
        return 0;
    }
    
    }
    signed main(){
        Miracle::main();
        return 0;
    }

    只关心生命值多少

    题意转化!变成新图!

    系数相同,带着常数一起消除!

  • 相关阅读:
    SQL优化总结(转)
    ORA-04030: 在尝试分配...字节(...)时进程内存不足的原因分析解决方法
    MyEclipse 在线安装SVN插件
    jboss+ejb entityManager操作数据库
    struts2标签#、%、$取值
    ejb+weblogic布署(转)
    ejb+jboss集群(转)
    myeclipse配置jboss(转载)
    list-列表练习
    python-循环小练习
  • 原文地址:https://www.cnblogs.com/Miracevin/p/11061965.html
Copyright © 2011-2022 走看看