汤氏思考题解答

汤氏思考题:http://blog.renren.com/blog/348686342/802082372

原文摘录:汤氏动脑题:假设一个教室里有300个座位,有300个同学且每人拥有一个固定的座位,我们三个是最早进教室的并且随便坐在了别人的座位上,那么这时这个座位的同学来了之后也只能坐在其他人的座位上,进而影响更多的人。请从概率论的角度分析,仅由最初我三个人坐在别人位置上而导致300人到齐后坐在别人位置上的总人数。

假设当前有m个人进来,其中x个人没有坐在自己的位置上,其中n个人自己的座位是空的(显然这n个人只能是我们三个中的,故n<=3),这个状态用三维坐标(m,x,n)表示

那么现在再进来1个人后,

  • 假若他的位置被占(概率是n/(300-m)),
    • 若他走向那n个(其实就是我们3个其中的一个)人的座位(概率n/(300-m)),现在的状态变为(m+1,x+1,n-1)
    • 若他走向那300-m-n个人的座位(概率为(300-m-n)/(300-m)),现在的状态变为(m+1,x+1,n)
  • 假若他的位置没有被占(概率(300-m-n)/(300-m)),显然他将走向自己的位置,现在的状态变为(m+1,x,n)
初始状态,我们3个人进来,3个人都不在自己的位置:

  • (3,3,0)仅仅是我们3个人互相换了位置,有2种情况
  • (3,3,1)我们3个人只有一个人的位置是空,有297×3×3种情况
  • (3,3,2)我们3个人只有一个人的位置坐了人,有297×296×3×2种情况
  • (3,3,3)我们3个人座位都空着,有297×296×295种情况
四个加起来就是初始的情况总数,分别除以这个总数就是每个初始状态的概率。
okay,到现在,动归转移方程写好了,初始状态也搞定了,程序显而易见了,复杂度呢,时间和空间复杂度都是O(300×300×3),更一般的,如果是一共N个同学的,初始我们有M个人没坐自己座位,复杂度是O(MN^2)

代码如下:

#include <stdio.h>
#define N 300			//一共N个座位
double f[N+10][N+10][4] = {0};
int main()
{
	//四种初始情况的个数
	double A = 2;
	double B = (N-3) * 3 * 3;
	double C = (N-3) * (N-2) * 3 * 2;
	double D = (N-3) * (N-2) * (N-1);
	double E = A + B + C + D;
	double ans = 0;
	int m,x,n;
	//四种初始情况的概率
	f[3][3][0] = A / E;
	f[3][3][1] = B / E;
	f[3][3][2] = C / E;
	f[3][3][3] = D / E;
	//动归求解
	for(m = 3 ; m < N ; m++)
		for(x = 3 ; x <= m ; x++)
			for(n = 0 ; n <= 3 ; n++)
			{
				if(n)f[m+1][x+1][n-1] += f[m][x][n] * n * n/((N-m)*(N-m));
				f[m+1][x+1][n] += f[m][x][n] * n * (N-m-n)/((N-m)*(N-m));
				f[m+1][x][n] += f[m][x][n] * (N-m-n) / (N-m);
			}
	//ans即为最后的期望,f[N][0][0]是为了验证最后是否概率和为1
	for(n = 3 ; n <= N ; n++)
	{
		ans += n*f[N][n][0];
		f[N][0][0] += f[N][n][0];
	}
	printf("%lf %lf\n",ans,f[N][0][0]);
	return 0;
}
import java.util.Date;

public class Tangshi {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Date start = new Date();
		int N = 300;
		double f[][][] = new double[N + 10][N + 10][4];
		// 四种初始情况的个数
		double A = 2;
		double B = (N - 3) * 3 * 3;
		double C = (N - 3) * (N - 2) * 3 * 2;
		double D = (N - 3) * (N - 2) * (N - 1);
		double E = A + B + C + D;
		double ans = 0;
		int m, x, n;
		// 四种初始情况的概率
		f[3][3][0] = A / E;
		f[3][3][1] = B / E;
		f[3][3][2] = C / E;
		f[3][3][3] = D / E;
		// 动归求解
		for (m = 3; m < N; m++)
			for (x = 3; x <= m; x++)
				for (n = 0; n <= 3; n++) {
					if (n > 0)f[m + 1][x + 1][n - 1] += f[m][x][n] * n * n / ((N - m) * (N - m));
					f[m + 1][x + 1][n] += f[m][x][n] * n * (N - m - n) / ((N - m) * (N - m));
					f[m + 1][x][n] += f[m][x][n] * (N - m - n) / (N - m);
				}
		// ans即为最后的期望,f[N][0][0]是为了验证最后是否概率和为1
		for (n = 3; n <= N; n++) {
			ans += n * f[N][n][0];
			f[N][0][0] += f[N][n][0];
		}
		System.out.println(ans + " " + f[N][0][0]);
		Date end = new Date();
		System.out.println("Time Cost:" + (end.getTime() - start.getTime())
				+ "ms");// 计时
	}

}

java这个时间结果是31ms
最后的结果是16.387016,个人感觉有点小,似乎不太可靠。。。。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值