【高斯消元 求期望】HDU 4418 Time travel

KIDx的解题报告

 

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4418

 

题意:一个人在数轴上来回走,以pi的概率走i步i∈[1, m],给定n(数轴长度),m,e(终点),s(起点),d(方向),求从s走到e经过的点数期望

 

解析:设E[x]是人从x走到e经过点数的期望值,显然对于终点有:E[e] = 0

一般的:E[x] = sum((E[x+i]+i) * p[i])(i∈[1, m]) 

(走i步经过i个点,所以是E[x+i]+i)

 

建立模型:高斯消元每个变量都是一个互不相同的独立的状态,由于人站在一个点,还有一个状态是方向!例如人站在x点,有两种状态向前、向后,不能都当成一种状态建立方程,所以要把两个方向化为一个方向从而使状态不受方向的影响

实现:

n个点翻过去(除了头尾两个点~~~)变为2*(n-1)个点,例如:

6个点:012345  --->  0123454321

那么显然,从5开始向右走其实就是相当于往回走

然后方向就由两个状态转化成一个状态的,然后每个点就是只有一种状态了,对每个点建立方程高斯消元即可

 

bfs判断是否可以到达终点,顺便建立方程

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <queue>
#include <algorithm>
#include <math.h>
using namespace std;
#define M 205
#define eps 1e-8
int equ, var;
double a[M][M], x[M];

int Gauss ()
{
	int i, j, k, col, max_r;
	for (k = 0, col = 0; k < equ && col < var; k++, col++)
	{
		max_r = k;
		for (i = k+1; i < equ; i++)
			if (fabs (a[i][col]) > fabs (a[max_r][col]))
				max_r = i;
		if (k != max_r)
		{
			for (j = col; j < var; j++)
				swap (a[k][j], a[max_r][j]);
			swap (x[k], x[max_r]);
		}
		x[k] /= a[k][col];
		for (j = col+1; j < var; j++) a[k][j] /= a[k][col];
		a[k][col] = 1;
		for (i = 0; i < equ; i++) if (i != k)
		{
			x[i] -= x[k] * a[i][k];
			for (j = col+1; j < var; j++) a[i][j] -= a[k][j] * a[i][col];
			a[i][col] = 0;
		}
	}
	return 1;
}

//has[x]表示人在x点时的变量号,因为我们只用可达状态建立方程,所以需要编号
int has[M], vis[M], k, e, n, m;
double p[M], sum;

int bfs (int u)
{
	memset (has, -1, sizeof(has));
	memset (a, 0, sizeof(a));			//忘记初始化WA勒,以后得注意
	memset (vis, 0, sizeof(vis));
	int v, i, flg = 0;
	queue<int> q;
	q.push (u);
	k = 0;
	has[u] = k++;
	while (!q.empty ())
	{
		u = q.front ();
		q.pop ();
		if (vis[u]) continue;
		vis[u] = 1;
		if (u == e || u == n-e)		//终点有两个,你懂的~
		{
			a[has[u]][has[u]] = 1;
			x[has[u]] = 0;
			flg = 1;
			continue;
		}
		//E[x] = sum ((E[x+i]+i) * p[i])
		// ----> E[x] - sum(p[i]*E[x+i]) = sum(i*p[i])
		a[has[u]][has[u]] = 1;
		x[has[u]] = sum;
		for (i = 1; i <= m; i++)
		{
			//非常重要!概率为0,该状态可能无法到达,如果还去访问并建立方程会导致无解
			if (fabs (p[i]) < eps) continue;
			v = (u + i) % n;
			if (has[v] == -1) has[v] = k++;
			a[has[u]][has[v]] -= p[i];
			q.push (v);
		}
	}
	return flg;
}

int main()
{
	int t, s, d, i;
	scanf ("%d", &t);
	while (t--)
	{
		scanf ("%d%d%d%d%d", &n, &m, &e, &s, &d);
		n = 2*(n-1);
		sum = 0;
		for (i = 1; i <= m; i++)
		{
			scanf ("%lf", p+i);
			p[i] = p[i] / 100;
			sum += p[i] * i;
		}
		if (s == e)
		{
			puts ("0.00");
			continue;
		}
		//一开始向左,起点要变
		if (d > 0) s = (n - s) % n;
		if (!bfs (s))
		{
			puts ("Impossible !");
			continue;
		}
		equ = var = k;
		Gauss ();
		printf ("%.2f\n", x[has[s]]);
	}
    return 0;
}

 

你可能感兴趣的:(编程,C++,算法,ACM,概率期望)