bzoj3270

题意:给定一张图,边是双向的,2个人在图上走,对于每个点,在某个时刻有pi的概率停留在这个点,有1-pi的概率 等概率走向它周围的点,要求对于每个点i,这2个人在点i相遇的概率,注意此题在边上相遇不算相遇。

这题真是太神奇了,在我校集训队大爷InvUsr的讲解下终于是搞明白了,
对于每个状态,记f[i][j]表示a走到点i,b走到点j,期望经过多少个点,那么对于每个f[i][j],有(Σf[i][i])=1,并且对于每个点,在这个点相遇的概率和期望成正比,所以我们得出f[i][i]就是在i点相遇的期望
然后要列出dp方程,分4个情况考虑,一种是停留在原地,有2种是其中一个点走,另一个点不走,还有就是2个点一起走,列方程的时候注意假如f[i][j]由f[i'][j']转移,那么i'!=j'。
然后边界条件是f[a][b]=1,因为一开始是在a,b所以期望经过至少1个点

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 405;
double f[MAXN][MAXN], p[MAXN];
int n, m, i, j, k, x, y, z, begix, begiy, du[MAXN];
bool g[MAXN][MAXN];
int main()
{
	cin >> n >> m >> begix >> begiy;
	for(i = 1; i <= m; i ++)
		cin >> x >> y, g[x][y] = g[y][x] = 1, du[x] ++, du[y] ++;
	for(i = 1; i <= n; i ++)
		cin >> p[i];
	int N = n * n;
	for(i = 1; i <= n; i ++)
		for(j = 1; j <= n; j ++)
		{
			int num = (i - 1) * n + j, nexnum;
			if (i != j) f[num][num] = 1.0 - p[i] * p[j];
			else f[num][num] = 1.0;
			for(x = 1; x <= n; x ++)
				if (g[i][x] && x != j)
				{
					nexnum = (x - 1) * n + j;
					f[num][nexnum] -= p[j] * (1.0 - p[x]) / du[x];
				}
			for(y = 1; y <= n; y ++)
				if (g[j][y] && i != y)
				{
					nexnum = (i - 1) * n + y;
					f[num][nexnum] -= p[i] * (1.0 - p[y]) / du[y];
				}
			for(x = 1; x <= n; x ++)
				for(y = 1; y <= n; y ++)
					if (g[i][x] && g[j][y] && x != y)
					{
						nexnum = (x - 1) * n + y;
						f[num][nexnum] -= (1 - p[x]) / du[x] * (1 - p[y]) / du[y];
					}
		}
	f[(begix - 1) * n + begiy][N + 1] = 1;
	for(i = 1; i <= N; i ++)
	{
		int k = 0;
		for(j = i; j <= N; j ++)
			if (fabs(f[j][i]) >= 1e-9) {k = j; break;}
		if (!k) continue;
		for(j = 1; j <= N + 1; j ++)
			swap(f[i][j], f[k][j]);
		double sb = f[i][i];
		for(j = 1; j <= N + 1; j ++)
			f[i][j] /= sb;
		for(j = 1; j <= N; j ++)
			if (i != j && fabs(f[j][i]) >= 1e-9)
			{
				sb = f[j][i];
				for(k = 1; k <= N + 1; k ++)
					f[j][k] -= f[i][k] * sb;
			}
	}
	for(i = 1; i <= n; i ++)
		printf("%.6lf ", f[(i - 1) * n + i][N + 1]);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值