[bzoj 3270] 博物馆:高斯消元+期望转移

[bzoj 3270] 博物馆

http://www.lydsy.com/JudgeOnline/problem.php?id=3270%20%E4%BC%A0%E9%80%81%E9%97%A8)


乍一看比较难想到这是一道高斯消元的题目,因为概率不好转移,得不到方程。
但是反过来想,用f(a,b)来表示,两个人分别在a房间和b房间的期望。那么这个期望是可以通过与其相连的房间的期望累加得到的:

f[a,b]+=f[p,q]*p1

这里的f[p,q]是枚举的出发点,而p1是其对应的概率;

所以可以看出一个多元带有系数的方程,这才引出了高斯消元;
需要用一个函数对 点对进行编号 code(i,j)

特别注意的是:
a[code(a,b)][tot+1]=-1
a,b是初始状态,期望肯定是有一个1的,移项后得-1;

下见代码:

#include 
#include 
#include 
#include 
#include 
#define EPS 0.0000000001
#define cnt (n*n) 
using namespace std;

int n,m,a1,b,d[50],mp[50][50];
double a[500][500],p[50];

int code(int i,int j){return (i-1)*n+j;}

void build(int x,int y){
    if(x==a1&&y==b)a[code(x,y)][cnt+1]=-1;
    a[code(x,y)][code(x,y)]=-1;
    for(int i=1;i<=d[x];i++)
        for(int j=1;j<=d[y];j++){
            int tx=mp[x][i],ty=mp[y][j];//tx,ty枚举的可抵达的起始点;
            if(tx==ty)continue;
            double p1,p2; 
            if(tx==x)p1=p[tx];
            else p1=(1-p[tx])/(d[tx]-1);
            if(ty==y)p2=p[ty];
            else p2=(1-p[ty])/(d[ty]-1);
            a[code(x,y)][code(tx,ty)]+=p1*p2;
        }
} 

void Gauss(){
    for(int i=1;i<=cnt;i++){
        int j=i;
        while(j<=cnt&&abs(a[j][i])if(j>cnt)continue;
        if(j!=i)swap(a[i],a[j]);
        for(int j=1;j<=cnt;j++)if(j!=i){
            double t=(a[j][i])/a[i][i];
            for(int k=i;k<=cnt+1;k++)
                a[j][k]-=a[i][k]*t;
        }
    }
}

int main()
{
#ifdef YSW
    freopen("in.txt","r",stdin);
#endif
    scanf("%d%d%d%d",&n,&m,&a1,&b);
    for(int i=1;i<=m;i++){
        int x,y;scanf("%d%d",&x,&y);
        mp[x][++d[x]]=y;
        mp[y][++d[y]]=x;
    }
    for(int i=1;i<=n;i++)scanf("%lf",&p[i]),mp[i][++d[i]]=i;//可留在原地,所以起始点多了自己;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            build(i,j);
    Gauss();
    for(int i=1;i<=n;i++)
        printf("%.6lf ",a[code(i,i)][cnt+1]/a[code(i,i)][code(i,i)]);
    return 0; 
}

你可能感兴趣的:(高斯消元)