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;
}

只关心生命值多少

题意转化!变成新图!

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

 

posted @ 2019-06-20 22:58  *Miracle*  阅读(327)  评论(0编辑  收藏  举报