出界的概率

問題:

一個小島,表示爲一個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];
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章