[bzoj3270] 博物馆

[bzoj3270] 博物馆


和两个神仙讨论了一个晚上为啥是对的。。。迷了

好的我们先来看网上的答案(大概是?)

状态是f[i][j]表示一个人在 i 另一个在 j 的概率,我们先列出方程(这个方程不用说了应该都会的),

然后因为我们是从x,y开始,f[x][y]要加1,然后我们直接移项高消即可。

我:???


这道题主要是不好想怎么把 “ 初始状态是 x , y ” 代入进去(也就是说那个加一是怎么来的)。需要注意的是,这道题的状态其实是在指经过 f i,j 的概率(你可以想想一个DAG的情况你状态咋定义的)。

我们考虑再记一维,状态是 G[ i ][ j ][ k ]表示 i 步之后 到达某状态的概率。

然后不难发现,答案就是 ans[p] = sigma( i = 1 ~ inf )g[ i ][ p ][ p ] ,然后发现i-1到i的转移都是一样的

然后我们把 f [ p ] [ q ] 看作 sigma( i = 1 ~ inf )g[ i ][ p ][ q ],然后我们的转移显然是一样的,然后你加上的那个1,就相当于是g [ 0 ][ s ][ t ]。

然后这个方程就变得很显然了

  • 代码
#include
using namespace std;
const int N=30,M=1010;
int n,m;
#define g(x,y) ((x-1)*n+y)
typedef long double db;
int tot;
db eps=1e-8;
db p[N];
int cnt,hed[N],nxt[M],to[M],d[N];
inline void adde(int u,int v){
    cnt++;to[cnt]=v,nxt[cnt]=hed[u];hed[u]=cnt;
}
db f[N*N][N*N];
inline void build(int x,int y){
    int w=g(x,y);
    f[w][w]=-1.0;
    for(int i=hed[x];i;i=nxt[i]){
        int vx=to[i];
        for(int j=hed[y];j;j=nxt[j]){
            int vy=to[j];
            if(vx==vy)continue;
            int t=g(vx,vy);
            if(vx==x&&vy==y)f[w][t]+=p[vx]*p[vy];
            else if(vx==x)f[w][t]+=p[vx]*(1-p[vy])/d[vy];
            else if(vy==y)f[w][t]+=p[vy]*(1-p[vx])/d[vx];
            else f[w][t]+=(1-p[vx])*(1-p[vy])/d[vx]/d[vy];
        }
    }
}
int s,t;
inline void guass(){
    /*for(int i=1;i<=tot;++i){
        for(int j=1;j<=tot+1;j++)
            cout<eps){p=j;break;}
        }
        if(p==-1)continue;
        if(i!=p)
            for(int k=1;k<=tot+1;k++)
                swap(f[i][k],f[p][k]);
        for(int j=1;j<=tot;++j)if(i!=j){
            db d=f[j][i]/f[i][i];
            for(int k=1;k<=tot+1;k++){
                f[j][k]-=f[i][k]*d;
            }
        }
    }
}

int main()
{
    scanf("%d%d",&n,&m);
    scanf("%d%d",&s,&t);
    for(int i=1;i<=n;++i)adde(i,i);
    for(int i=1;i<=m;i++){
        int u,v;scanf("%d%d",&u,&v);
        adde(u,v);adde(v,u);
        d[u]++,d[v]++;
    }
    for(int i=1;i<=n;i++)scanf("%Lf",&p[i]);
    tot=n*n;
    f[g(s,t)][tot+1]=-1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            build(i,j);
    guass();
    for(int i=1;i<=n;i++){
        printf("%.6Lf ",f[g(i,i)][tot+1]/f[g(i,i)][g(i,i)]);
    }
}

 

你可能感兴趣的:([bzoj3270] 博物馆)