求期望问题小结 From ZJUTBBS

       前几天一直纠结在《地下迷宫》那题中,苦苦思索无果。在一个月黑风高的夜晚,终于开窍,原来期望就是这么回事。赛后DK跟我说求期望很简单,我以为是诓我去做这个题目。我心说,您老人家看什么不简单啊,何况你还是期望控。现在觉得果然是简单的,用我的人品做担保,真的很简单。
       先来看一个小例子:如图,从起点0,走到终点4。每次等概率地随机选择一条路走,(比如当前在0点,下一步分别有1/3的可能走到1,2,3点;对于1 点,下一步各有1/3的可能走到1点,0点,2点),求平均需要用几步走到终点4,也就是求走到4点所花步数的期望。

分析:
       
要从0走到4,从第一步的角度来看,无非是三种途径:

先走到1,然后经过若干过程从1走到4

先走到2,然后经过若干过程从2走到4

先走到3,然后经过若干过程从3走到4
      
假如我们已经知道了从123走到4所要花的平均步数分别是E(1)E(2)E(3),那么从0走到4的步数,有三种可能:E(1)+1 E(2)+1E(3)+1,而且这三种是等概率的。那么从0走到4的平均步数就是(E(1)+1+E(2)+1+E(3)+1)/3。现在我们并不知道 E(1)E(2)E(3)的值,得到的只是一个方程E(0)=(E(1)+E(2)+E(3))/3+1
       
同样的,对于点2,我们可以列出方程E(2)=(E(0)+E(1)+E(3)+E(4))/4+1
       
有人说了,我靠,E(4)是什么东东?
       E(4)
当然就是从4点走到4点所花的平均步数,显然有E(4)=0
       
联立方程组
        E(0)=(E(1)+E(2)+E(3))/3+1
        E(1)=(E(0)+E(1)+E(2))/3+1
        E(2)=(E(0)+E(1)+E(3)+E(4))/4+1
        E(3)=(E(0)+E(2)+E(4))/3+1
        E(4)=0
       
图是我随手画的,求出来的解不整,保留两位小数如下:
       E[0]=8.38
       E[1]=9.14
       E[2]=6.90
       E[3]=6.10
       E[4]=0.00
       
现在只要会编程解方程组就大功告成了。线性代数里讲过,可以用矩阵来表示线性方程组,用高斯消元法对矩阵进行处理,即可求解。有的小朋友没学线性代数,有 的和我一样学完后早忘到脚后跟去了。我是从网上搜了个高斯消元的代码来研究学习的。要不老衲买一赠一,顺道把高斯消元也解释一下吧。
-----------------------
促销大派送之高斯消元---------------------------
   
上述方程组整理可得(为了减少精度损失,在某些式子上乘个常数,使系数整一点):
3*E(0)  -E(1)  -E(2) -E(3)+0*E(4)=3
-E(0)+2*E(1)  -E(2)+0*E(3)+0*E(4)=3
-E(0)  -E(1)+4*E(2)  -E(3) -E(4)=4
-E(0)-0*E(1)  -E(2)-3*E(3)  -E(4)=3
0*E(0) +0*E(1) +0*E(2)+0*E(3)  +E(4)=0
   
我们用一个5*5的二维数组a来描述等号左边各项的系数,用数组b来表示等号右边的常数项。直接用一个5*6的矩阵来表示当然也是可以的。数组的数据类型为double
           a              b
[0]  3 -1 -1 -1  0 | 3
[1] -1  2 -1  0  0 |3
[2] -1 -1  4 -1 -1| 4
[3] -1  0 -1  3 -1 | 3
[4]  0 0  0  0 1  | 0
   
注意,在我的叙述中,行号列号都是从0开始编的。
   
由方程组的性质,我们知道,可以给某一行乘上一个非零常数,可以把某一行乘一个非零常数加到另一行上去,可以任意调换两行的位置。这些操作都不影响方程组 的解,叫做行初等变换。我们利用行初等变换来处理矩阵。首先,我想让左边只留一个E(0),其他的E(0)系数都消掉。我们选择保留第0行,在第12 3行上都加上第0行的1/3,矩阵变成了这样(只显示两位小数,下同):
   3.00 -1.00  -1.00  -1.00  0.00|   3.00
   0.00  1.67  -1.33  -0.33  0.00|   4.00
   0.00 -1.33   3.67  -1.33 -1.00|   5.00
   0.00 -0.33  -1.33   2.67 -1.00|   4.00
   0.00  0.00   0.00   0.00  1.00|   0.00
   
0行就固定不动了,接着我让下面四行只留一个E(1),其他的消掉。方法是在第2行上加上第1行的4/5,在第3行上加上第1行的1/5。处理后:
   3.00 -1.00  -1.00  -1.00  0.00|   3.00
   0.00  1.67  -1.33  -0.33  0.00|   4.00
   0.00  0.00   2.60  -1.60 -1.00|   8.20
   0.00  0.00  -1.60   2.60 -1.00|   4.80
   0.00  0.00   0.00   0.00  1.00|   0.00
   
从上面的步骤可以看出,在消元的时候,我们需要从下面剩下的行中选择一个需要保留的行,这里称作主元行。选择的标准是什么?比如上一步,我们完全可以把第 1行加上第3行的5倍,把第2行加上第3行的-4倍。我看的那篇文章上说,选择该列中绝对值最大的那一行作为主元行,这样可以减少精度损失。好吧,我们相 信这个说法。假设a[1][1]这个位置不是1.67,而是0.67,那么这一列中绝对值最大的系数就是a[2][1]-1.33(注意,第0行是不参 与比较的,它已经固定下来了)。那我们就交换第12行,把-1.33这一行提到上面,然后再执行消元操作,把这一列的下面都消成0
   
如果处理到某一列的时候,发现这一列剩下的系数竟然全是0了,比如这样的:
    1 2 3 4| 5
    0 6 7 8| 9
    0 0 0 1| 2
    0 0 0 2| 4
   
2列剩下的全是0了,找不到主元行了,这说明该矩阵的秩小于元数,方程组解不出唯一解来。通俗点说,就是这些方程里有水货,表面上看是4个方程,可仔细一瞧,第2行和第3行本质上是一样的,当然解不出。
   
好了,回到我们刚才的例子,通过一番处理之后,矩阵的左下角全变成0了。这称为行阶梯式。
   3.00 -1.00  -1.00  -1.00  0.00|   3.00
   0.00  1.67  -1.33  -0.33  0.00|   4.00
   0.00  0.00   2.60  -1.60 -1.00|   8.20
   0.00  0.00   0.00   1.62 -1.62|   9.85
   0.00  0.00   0.00   0.00  1.00|   0.00
   
根据最后一行,可以确定E(4)的值,我们把它存到x[4]里。把E(4)代入到3式,可以解出E(3);把E(3)E(4)代入2式,解出E(2)……
   
代码实现如下:

	#define EPS 1e-10
	int N;
	#define MAX 100
	double a[MAX][MAX],b[MAX],x[MAX];
	bool flag;
	
	double ab(double x)
	{
	    return (x>=0)?x:-x;
	}
	void Gauss()
	{
	        flag=1;
	        double maxi,d;
	        int index,i,j,k;
	        for(k=0;k<N;k++)
	        {
	                maxi=0;
	                for(i=k;i<N;i++)//找该列绝对值最大的行
	                {
	                        if(ab(a[i ][k])>maxi)
	                        {
	                                index=i;
	                                maxi=ab(a[i ][k]);
	                        }
	                }
	                if(maxi<EPS)//如果剩下的全是0,失败返回
	                {
	                        flag=0;
	                        return;
	                }
	                if(index!=k)//把主元行交换到上面来
	                {
	                        swap(b[index],b[k]);
	                        for(j=k;j<N;j++)
	                                swap(a[index][j],a[k][j]);
	                }
	                for(i=k+1;i<N;i++)//把非主元行的系数消掉
	                {
	                        d=a[i ][k]/a[k][k];
	                        b[i ]-=b[k]*d;
	                        a[i ][k]=0;
	                        for(j=k+1;j<N;j++)
	                                a[i ][j]-=a[k][j]*d;
	                }               
	        }
	        //至此,已经得到一个行阶梯式
	        for(i=N-1;i>=0;i--)//从底向上依次代入求解
	        {
	                for(j=i+1;j<N;j++)
	                        b[i ]-=a[i ][j]*x[j];
	                x[i ]=b[i ]/a[i ][i ];
	        }
	}

------------------------赠品End------------------------
   
高斯消元解方程组的复杂度是O(N^3),回到地下迷宫这题,对所有的连通点联立方程组。连通点的个数不超过100,代码见这里

http://bbs.zjut.com/viewthread.php?tid=1167909&page=1#pid6158985(链接已经失效)

扩展1POJ 3682 King Arthur's Birthday Celebration
    http://acm.pku.edu.cn/JudgeOnline/problem?id=3682
   
题目大意是说扔硬币,有p的概率是正面,1-p的概率是反面。每天扔一次,直到累计扔出k个正面为止。在扔硬币期间,第一天花1千块钱,第二天花3千,第三天花5
……
   
求平均扔几次会停止,平均会花多少钱。

   
k=3p=0.5为例,按已扔出几个正面来区分,共有4种状态。各状态之间按如下的概率转移。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值