[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 <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#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])<EPS)j++;
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;
}