hdu4418 Time travel 【期望+dp】

本文探讨了一道关于在数轴上随机行走的问题,通过建立数学模型和使用高斯消元法解决从起点到终点经过点数的期望值计算问题。

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

题目刚开始不是很懂,读懂了又不会求期望,看了好久题解才渐渐有些明白,脑残~~

至于求期望的方法见《数论--期望》。我也是看了那个简单的求期望的公式才明白为什么E(X)=SUM{(E(X+i)+i)*p[i]}

对于在点X,下次可以走到的点为X+i,每个点走到终点的概率为P[i],由于是从X走到X+i,所以要E(x+i)+i才是变量值,p[i]为概率。然后各自相乘、

------------------------------------------------------------------------------------------------------------------

Description

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

Solution

解析:设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判断是否可以到达终点,顺便建立方程

----------------------------------------------------------------------------------------

注意点:

1.将转移方程的右边进行分解位移,构建的方程为E[X]-SUM(E(X+i)*p[i])=SUM(P[i]*i),一共cnt个方程

cnt为bfs得到的可达点,为什么会出现不可达点呢,因为当某些点的概率为0时就有可能出现不可达点。

2.注意由于方向不同,所以转移困难,但是可以利用用2倍的长度来表示,这技巧需要牢记

3.代码时借鉴kuangbin的,但是他建立的方程和求解过程不懂,所以改成自己之前写的,1a,好开心!!原来自己也有可以用自己的方法做出来的、、、

#include<stdio.h>
#include<string.h>
#include <iostream>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
#define eps 1e-9
const int maxn=250;
double a[maxn][maxn],x[maxn];
int equ,var;
int num[maxn];
int cnt,m,n,N;
double p[maxn];

int Gauss() {
	int i,j,k,col,max_r;
	double temp;
	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(fabs(a[max_r][col])<eps)  {
			//说明有无穷解或无解 
			return 0;
		}
		if(k!=max_r) {
			for(j=col; j<var+1; j++)
				swap(a[k][j],a[max_r][j]);
		}
		for(i=k+1; i<equ; i++) {
			if(fabs(a[i][col])>eps) {
				temp=a[i][col]/a[k][col];
				for(j=col; j<var+1; j++) {
					a[i][j]-=a[k][j]*temp;
				}
			}
		}
	}
	//有无解 
	for(i=k; i<equ; i++) if(fabs(a[i][var])>eps) return -1;

	for(i=var-1; i>=0; i--) {
		temp=a[i][var];
		for(j=i+1; j<var; j++) {
			if(fabs(a[i][j])>eps)
				temp-=a[i][j]*x[j];
		}
		x[i]=temp/a[i][i];
	}
	return 1;
}
void bfs(int s) {
	memset(num,-1,sizeof(num));
	queue<int>que;
	cnt=0;
	num[s]=cnt++;
	que.push(s);
	while(!que.empty()) {
		int t=que.front();
		que.pop();
		for(int i=1; i<=m; i++) {
			if(fabs(p[i])<eps) continue;
			int temp=(t+i)%n;
			if(num[temp]==-1) {
				num[temp]=cnt++;
				que.push(temp);
			}
		}
	}
}
int main() {
#ifndef ONLINE_JUDGE
	freopen("in.txt","r",stdin);
#endif
	int s,e,d,t;
	cin>>t;
	while(t--) {
		cin>>N>>m>>e>>s>>d;
		for(int i=1; i<=m; i++) cin>>p[i],p[i]/=100;

		if(e==s) {
			cout<<"0.00"<<endl;
			continue;
		}

		n=2*(N-1);
		if(d==1)  s=n-s;
		bfs(s);
		if(num[e]==-1&&num[n-e]==-1) {
			cout<<"Impossible !"<<endl;
			continue;
		}
		equ=var=cnt;
		var++;
		memset(a,0,sizeof(a));
		memset(x,0,sizeof(x));
		//构建方程矩阵
		for(int i=0; i<n; i++) {

			if(num[i]!=-1) {
				if(i==e||i==n-e) {
					a[num[i]][num[i]]=1;
					x[num[i]]=0;
					continue;
				}
				a[num[i]][num[i]]=1;
				for(int j=1; j<=m; j++) {
					int t=(i+j)%n;
					if(num[t]!=-1) {
						a[num[i]][num[t]]-=p[j];
						a[num[i]][var]+=j*p[j];
					}
				}
			}
		}
		int ens=Gauss();//cout<<"ens: "<<ens<<endl;
		if(ens==1) printf("%.2f\n",x[num[s]]);
		else cout<<"Impossible !"<<endl;
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值