出界的概率

19 篇文章 0 订阅
8 篇文章 0 订阅

问题:

一个小岛,表示为一个N×N的方格,从(0,0)到(N-1, N-1),一个人站在岛上,位置(x, y),他可以上下左右走,一步一个格子,他选择上下左右的可能性是一样的。当他走出小岛,就意味着死亡。假设他要走k步,请问他死亡的概率有多大?


分析I:

要求概率,首先想到计算出所有路径的种数N,以及出界的路径种数M,死亡的概率就是N/M了。

计算路径种数可以用DP的思想:

设走k步从位置(x, y)到达(i,j)的路径种数为f[k][i][j],那么:

f[k][i][j] = f[k-1][i-1][j]+f[k-1][i+1][j] +f[k-1][i][j-1] +f[k-1][i][j+1] 。

所以很快写出如下的代码:

double ProbabilityAndCount(int x0, int y0, int N, int k, int &innerCount, int &outerCount){
	static const int directons[4][2]={{0,1}, {0,-1}, {1, 0}, {-1, 0}};
	innerCount = 0;
	outerCount = 0;
	if(N == 1)
		return 1.0;
	vector<vector<int>>memos(2, vector<int>(N * N, 0));
	int memoIndex = 0;
	memos[memoIndex][y0 * N + x0] = 1;
	for(int stepi = 1; stepi <= k; ++stepi){
		int preMemoIndex = memoIndex;
		memoIndex = 1 - memoIndex;
		for(int y = 0; y < N; ++y){
			for(int x = 0; x < N; ++x){
				//更新正好第stepi步走出界的路线种数
				if(y == 0 || y == N - 1)
					outerCount += memos[preMemoIndex][y * N + x];
				if(x == 0 || x == N - 1)
					outerCount += memos[preMemoIndex][y * N + x];
				//更新走stepi步后,走到(x, y)位置处的路线种数
				memos[memoIndex][y * N + x] = 0;
				for(int dir = 0; dir < 4; ++dir){//遍历4个邻居
					int nx = x + directons[dir][0];
					int ny = y + directons[dir][1];
					if(nx >= 0 && ny >= 0 && nx < N && ny < N)
						memos[memoIndex][y * N + x] += memos[preMemoIndex][ny * N + nx];
				}
			}
		}
	}
	innerCount =  std::accumulate(memos[memoIndex].begin(), memos[memoIndex].end(), 0);
	return (double)outerCount / (outerCount + innerCount);//返回走出界的概率
}

然而,上面的代码是 不正确的 ! 

代码中出界的路径长度是不一样的,所以出界路径的概率并不一样,不能够用路径总数来计算出界概率!

解决办法:

每一步的概率都是0.25,那么长度为k的路径的概率就为0.25^k,将所有出界的路径的概率加起来即可:

double Probability(int x0, int y0, int N, int k){
	static const int directons[4][2]={{0,1}, {0,-1}, {1, 0}, {-1, 0}};
	if(N == 1)
		return 1.0;
	double res = 0;

	vector<vector<int>>memos(2, vector<int>(N * N, 0));
	int memoIndex = 0;
	memos[memoIndex][y0 * N + x0] = 1;
	double probalityBase = 0.25;
	for(int stepi = 1; stepi <= k; ++stepi, probalityBase *= 0.25){
		int preMemoIndex = memoIndex;
		memoIndex = 1 - memoIndex;
		for(int y = 0; y < N; ++y){
			for(int x = 0; x < N; ++x){
				//更新正好走出界的概率(加上第stepi步走出界的概率)
				if(y == 0 || y == N - 1)
					res += probalityBase * memos[preMemoIndex][y * N + x];
				if(x == 0 || x == N - 1)
					res += probalityBase * memos[preMemoIndex][y * N + x];
				//更新走stepi步后,走到(x, y)位置处的路线种数
				memos[memoIndex][y * N + x] = 0;
				for(int dir = 0; dir < 4; ++dir){//遍历4个邻居
					int nx = x + directons[dir][0];
					int ny = y + directons[dir][1];
					if(nx >= 0 && ny >= 0 && nx < N && ny < N)
						memos[memoIndex][y * N + x] += memos[preMemoIndex][ny * N + nx];
				}
			}
		}
	}
	return res;
}

分析II:

实际我们可以不从路径种数入手,直接从概率入手,仍然是DP思想:

设从(i,j)走k步出界的概率为f[k][i][j],那么:

f[k][i][j] = (f[k-1][i-1][j]+f[k-1][i+1][j] +f[k-1][i][j-1] +f[k-1][i][j+1]) * 0.25 ,

若i,j已经出界,那么f[...][i][j] =1;

具体实现:时间复杂度O(k*N*N),空间复杂度O(N*N)

double Probability2(int x0, int y0, int N, int k){
	static const int directons[4][2]={{0,1}, {0,-1}, {1, 0}, {-1, 0}};
	vector<vector<double>>memos(2, vector<double>(N * N, 0));
	int memoIndex = 0;
	for(int stepi = 1; stepi <= k; ++stepi){
		int preMemoIndex = memoIndex;
		memoIndex = 1 - memoIndex;
		for(int y = 0; y < N; ++y){
			for(int x = 0; x < N; ++x){
				memos[memoIndex][y * N + x] = 0;
				for(int dir = 0; dir < 4; ++dir){//遍历4个邻居
					int nx = x + directons[dir][0];
					int ny = y + directons[dir][1];
					memos[memoIndex][y * N + x] += (nx >= 0 && ny >= 0 && nx < N && ny < N ? memos[preMemoIndex][ny * N + nx] : 1) * 0.25;
				}
			}
		}
	}
	return memos[memoIndex][y0 * N + x0];
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值