BZOJ 3270 博物馆

本文介绍了一个关于在城堡博物馆中两个朋友寻找彼此的概率问题。利用高斯消元法解决两个个体在不同房间相遇的概率计算问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

有一天Petya和他的朋友Vasya在进行他们众多旅行中的一次旅行,他们决定去参观一座城堡博物馆。这座博物馆有着特别的样式。它包含由m条走廊连接的n间房间,并且满足可以从任何一间房间到任何一间别的房间。
两个人在博物馆里逛了一会儿后两人决定分头行动,去看各自感兴趣的艺术品。他们约定在下午六点到一间房间会合。然而他们忘记了一件重要的事:他们并没有选好在哪儿碰面。等时间到六点,他们开始在博物馆里到处乱跑来找到对方(他们没法给对方打电话因为电话漫游费是很贵的)
不过,尽管他们到处乱跑,但他们还没有看完足够的艺术品,因此他们每个人采取如下的行动方法:每一分钟做决定往哪里走,有Pi 的概率在这分钟内不去其他地方(即呆在房间不动),有1-Pi 的概率他会在相邻的房间中等可能的选择一间并沿着走廊过去。这里的i指的是当期所在房间的序号。在古代建造是一件花费非常大的事,因此每条走廊会连接两个不同的房间,并且任意两个房间至多被一条走廊连接。
两个男孩同时行动。由于走廊很暗,两人不可能在走廊碰面,不过他们可以从走廊的两个方向通行。(此外,两个男孩可以同时地穿过同一条走廊却不会相遇)两个男孩按照上述方法行动直到他们碰面为止。更进一步地说,当两个人在某个时刻选择前往同一间房间,那么他们就会在那个房间相遇。
两个男孩现在分别处在a,b两个房间,求两人在每间房间相遇的概率。

Input

第一行包含四个整数,n表示房间的个数;m表示走廊的数目;a,b (1 ≤ a, b ≤ n),表示两个男孩的初始位置。
之后m行每行包含两个整数,表示走廊所连接的两个房间。
之后n行每行一个至多精确到小数点后四位的实数 表示待在每间房间的概率。
题目保证每个房间都可以由其他任何房间通过走廊走到。

Output

输出一行包含n个由空格分隔的数字,注意最后一个数字后也有空格,第i个数字代表两个人在第i间房间碰面的概率(输出保留6位小数)
注意最后一个数字后面也有一个空格

Sample Input

2 1 1 2
1 2
0.5
0.5

Sample Output

0.500000 0.500000

HINT

对于100%的数据有 n <= 20,n-1 <= m <= n(n-1)/2

Source

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

高斯消元~

根据题目建图,同时记录每个点的度数du[i]。

我们把两人走的点记在同一个数组a[k][k]中,状态k=d(i,j)表示A在i点,B在j点。

每个点输入的概率为gl[i],走到它相邻点的概率就是(1.0-gl[i])/(double)du[i]。

用a[i][j]表示关于状态i的方程中状态j的系数,那么我们就需要找出状态之间的关系。设z[d(i,j)]表示状态d(i,j)的期望到达次数,则

z[d(i,j)]=z[d(i,j)]*gl[i]*gl[j]+z[d(kkz1,j)]*gl[j]*k[kkz1](kkz1与i直接相连)+z[d(i,kkz2)]*gl[i]*k[kkz2](kkz2与j直接相连)+z[d(kkz1,kkz2)]*k[kkz1]*k[kkz2]。

然后把z[d(i,j)]移到右面即成为一个方程。同理我们可以列出n个方程,显然有唯一解。

要注意的是因为是从d(a,b)出发的,所以d(a,b)要有一个常数项1,移项后变为-1。

另外,d(i,i)是不能用于转移其他状态的,因为两人相遇后就停止游荡,这里要特判一下~


#include<cstdio>
#define d(u,v) (u+(v-1)*n)

int n,m,x,y,aa,bb,du[21],w[401],ne[401],fi[21],cnt;
double gl[21],a[401][402],k[21];

int read()
{
	int totnum=0,f=1;char ch=getchar();
	while(ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0' && ch<='9') {totnum=(totnum<<1)+(totnum<<3)+ch-'0';ch=getchar();}
	return totnum*f;
}

void add(int u,int v)
{
	w[++cnt]=v;ne[cnt]=fi[u];fi[u]=cnt;
	w[++cnt]=u;ne[cnt]=fi[v];fi[v]=cnt;
}

void guass(int n)
{
	for(int i=1;i<n;i++)
	{
		for(int j=i+1;j<=n+1;j++) a[i][j]/=a[i][i];a[i][i]=1;
		for(int j=i+1;j<=n;j++)
		{
			for(int k=i+1;k<=n+1;k++) a[j][k]-=a[j][i]*a[i][k];
			a[j][i]=0;
		}
	}
	for(int i=n;i>1;i--)
	{
		for(int j=i+1;j<=n+1;j++) a[i][j]/=a[i][i];a[i][i]=1;
		for(int j=i-1;j;j--)
		{
			for(int k=i+1;k<=n+1;k++) a[j][k]-=a[j][i]*a[i][k];
			a[j][i]=0;
		}
	}
}

int main()
{
	n=read();m=read();aa=read();bb=read();
	for(int i=1;i<=m;i++)
	{
		x=read(),y=read();add(x,y);du[x]++,du[y]++;
	}
	for(int i=1;i<=n;i++) scanf("%lf",&gl[i]),k[i]=(1.0-gl[i])/(double)du[i];
	for(int i=1;i<=n;i++)
	  for(int j=1;j<=n;j++)
	  {
	    	a[d(i,j)][d(i,j)]-=1.0;
	    	if(i!=j) a[d(i,j)][d(i,j)]+=gl[i]*gl[j];
	    	for(int z=fi[j];z;z=ne[z]) if(i!=w[z]) a[d(i,j)][d(i,w[z])]+=gl[i]*k[w[z]];
	    	for(int z=fi[i];z;z=ne[z]) if(j!=w[z]) a[d(i,j)][d(w[z],j)]+=k[w[z]]*gl[j];
	    	for(int z=fi[i];z;z=ne[z])
	    	  for(int r=fi[j];r;r=ne[r]) if(w[z]!=w[r]) a[d(i,j)][d(w[z],w[r])]+=k[w[z]]*k[w[r]];
	  }
	a[d(aa,bb)][n*n+1]+=-1.0;
	guass(n*n);
	for(int i=1;i<=n;i++) printf("%.6lf ",a[d(i,i)][n*n+1]);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值