首页 > 代码库 > 【POJ】3744 Scout YYF I (概率DP+矩阵优化)

【POJ】3744 Scout YYF I (概率DP+矩阵优化)

题目大意:走一步概率为p,走两步为1-p,x[i]代表第i个地雷的位置,求走出的概率为多少。

思路:设p[i]为走到i格的概率,那么走出去的概率为(1-p[x[i]])累乘

假如把整个路程分成若干段的话,以地雷为节点,可以发现p(x[i-1]~x[i])累乘,也是答案。可能说的不是很清楚,代码中可以看的比较清楚。

这边要说的是由于数据量比较大,并且数据之间又是乘法,所以会造成超时的情况。

一个方法便是利用矩阵快速幂的方法。

这边我介绍一下这个矩阵的一些意义吧。方法就不说了,大家可以百度大神代码,说的比较清楚

开辟一个二维矩阵,走一步概率为p,走两步概率为1-p

那么这个二维矩阵为

p 1-p

1   0   

p表示的是从起始位置走到当前位置的概率。(这边为第二个位置)(初始为第一个位置)

1-p表示从起始位置的上一个位置走两步到达当前位置的下一个位置的概率。

1表示的是从起始位置走到上一个位置的概率。

0表示从起始位置的上一个位置走两步到当前位置的下一个位置的概率。

若我们将该矩阵平方,便得到

p^2+1-p   p(1-p)

p                1-p

根据矩阵乘法的过程,我们不难推断,p^2+1-p便是从初始位置到达第三个位置的概率。

以此类推其他的三个变量。

其他问题在代码中说明,如果有问题欢迎讨论~~~

AC代码(copy from kuangbin):

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
struct M
{
	double m[2][2];
};
M mut(M a, M b)
{
	M c;
	for (int i = 0; i < 2;i++)
	for (int j = 0; j < 2; j++)
	{
		c.m[i][j] = 0;
		for (int k = 0; k < 2; k++)
			c.m[i][j] += a.m[i][k] * b.m[k][j];
	}
	return c;
}
M pow_mut(M a, int k)
{
	M c;
	memset(c.m, 0, sizeof(c.m));
	c.m[0][0] = 1;
	c.m[1][1] = 1;
	while (k)
	{
		if(k&1)c = mut(c, a);
		a = mut(a, a);
		k >>= 1;
	}
	return c;

}
int main()
{
	int pos[11];
	int n;
	double p;
	while (cin>>n>>p)
	{
		for (int i = 1; i <= n; i++)
			scanf("%d", &pos[i]);
		sort(pos+1, pos + n+1);
		M temp;
		temp.m[0][0] = p;
		temp.m[0][1] = 1 - p;
		temp.m[1][0] = 1;
		temp.m[1][1] = 0;
		double ans;
		M mid = pow_mut(temp, pos[1] - 1);
		ans = 1-mid.m[0][0];
		for (int i = 2; i <= n; i++)
		{
			if (pos[i] == pos[i - 1])
				continue;
			mid = pow_mut(temp, pos[i] - pos[i - 1]-1);//这边减1是因为你通过了x[i]的地雷,说明你现在所站的应该是x[i]+1的位置
			ans *= (1 - mid.m[0][0]);
		}
		printf("%.7f\n", ans);
	}
	return 0;
}



【POJ】3744 Scout YYF I (概率DP+矩阵优化)