題目描述
現在有兩個好友a和b,住在一片長有蘑菇的由n*m個方格組成的草地,a在(1,1),b在(n,m)。現在a想要拜訪b,由於她只想去b的家,所以每次她只會走(i,j+1)或(i+1,j)這樣的路線,在草地上有k個蘑菇種在格仔裡(多個蘑菇可能在同一方格),問:a如果每一步隨機選擇的話(若她在邊界上,則只有一種選擇),那麼她不碰到蘑菇走到b的家的概率是多少?
輸入描述:
第一行n,m,k(1 ≤ n,m ≤ 20, k ≤ 100),n,m為草地大小,接下來k行,每行兩個整數x,y,代表(x,y)處有乙個蘑菇。
輸出描述:
輸出一行,代表所求概率(保留到2位小數)
示例1
輸入
2 2 1
2 1輸出
0.50
分析:首先想到的辦法是,求出從左上角到右下角所有的路徑數目,以及不包含一顆蘑菇的路徑數目,二者相除,便得到了a碰不到蘑菇走到b的家的概率,這可以用dfs來解決,三下五除二,就乙個dfs出來了:
void awalkdfs(vector
> &map,int i,int j,int pathmushromcount,int &a,int &b)
awalkdfs(map, i, j + 1, pathmushromcount + map[i][j], a, b);//toward the right
awalkdfs(map, i+1, j, pathmushromcount + map[i][j], a, b);//toward the down}}
完全是瞎做!這樣的dfs 是指數時間,因為要窮舉所有的可能,沒有剪枝,別說答案是否正確,就連時間都不允許!
於是乎,稍加思考,就可以改進為動態規劃:
(1) 假設 fi
j 表示到達ma
p[i]
[j] 的總路徑數目,由於每一步只能想右或向下,則它依賴於左邊和上邊的狀態,即到達fi
j 的路徑數等於到達左邊fi
,j−1
的路徑數加上到達到fi
−1,j
的路徑數:fi
j=//************2. initialize the first row**************
for (int j = 1; j0][j] = 1;
h[0][j] = h[0][j - 1];
if (map[0][j]>0) h[0][j] = 0;
}for (int i = 1; ifor (int j = 1; j1][j] + p[i][j - 1];
if (map[i][j]>0) h[i][j] = 0;
else
}return (double)h[n - 1][m - 1] / p[n - 1][m - 1];
}然而求解的結果任然是錯誤的,不過,求解的路徑數目是正確的!而且求解路徑數目的速度降到了o(
nm) !
進一步分析題目發現,其實發現a走到每乙個格仔的概率p是不一樣的,拿其中乙個算例來分析,如圖所示:
比如邊界上的格仔:
(1) 左上角map[0][0]=0, 到達的概率是1;
(2) 第一行,對於任意p[0][j],它只能從左邊一格到達,如果格仔僅有一行,a在map[0][j] 的時候只能走到map[0][j+1]。
其餘邊界分析類似…..
對於最右下角(目標)格仔,格仔map[n-1][m-2] (下標從0開始)、map[n-2][m-1] 都只能以1的概率到達此格仔。
基於這樣的分析,假設gi
j 表示
a 到達格仔ma
p[i]
[j]不碰見蘑菇的概率,同樣,除去邊界,它可以由gi
−1,j
及gi,
j−1 表示,所以有以下的狀態方程gi
j=⎧⎩
⎨⎪⎪⎪
⎪⎪⎪⎪
⎪⎪⎪⎪
⎪⎪⎪⎪
⎪⎪⎪⎪
⎪⎪⎪⎪
⎪⎪⎪⎪
⎪⎪⎪⎪
⎪⎪⎪⎪
⎪⎪⎪⎪
⎪⎪⎪⎪
⎪⎪⎪1
,i=j
=0,(
第乙個格
子不能有
蘑菇,否
則後面都
不用打算
了)0,
map[
i][j
]>0,
(若某個
格仔有蘑
菇,則到
達此格仔
不碰到蘑
菇的概率
為0)1
2gi−
1,j+
12gi
,j−1
,i>=1,
j>=11
2g0,
j−1,
i=0,
j>=1,
n>1,
(上圖中
第一行綠
色區域)
g0,j
−1,i
=0,j
>=1,
n=1,
(僅一行
時左邊格
只能向右
,即以1
的概率到
達(i,
j))1
2gi−
1,0,
j=0,
i>=1,
m>1(
上圖中第
一列綠色
區域)g
i−1,
0,j=
0,i>=1,
m=1,
(僅一列
時左邊格
只能向下
,即以1
的概率到
達(i,
j))g
i−1,
j+gi
,j−1
,i=n
−1,j
=m−1
,n,m
>1,
(圖中的
目標格仔
) 上面狀態方程看似繁雜,但核心思想只有乙個:
gij
由gi−
1,j及
gi,j
−1轉換
而來
只不過不同的位置,這個轉換概率不同,所以導致了一系列邊界的處理。
最終的**如下(牛客網測試通過,上圖就是所得出的動態規劃表資料):
double awalk_dp(vector
> &map)
//************2. initialize the first row**************
for (int j = 1; jif (n>1) p[0][j] = p[0][j-1]*0.5;
else p[0][j] = p[0][j - 1] * 1.0;
if (map[0][j]>0) p[0][j] = 0.0;
}//************3. calculate no-boundary area ***********
for (int i = 1; i1; ++i)
for (int j = 1; j1; ++j)
//***********4 coping with boundary*********
for (int i = 1,j=m-1; j>0 && i < n-1; i++)
for (int j = 1,i=n-1;i>0 && j < m-1; j++)
if (n>1 && m>1)
p[n - 1][m - 1] =1.0 * p[n-2][m-1] + 1.0*p[n-1][m-2];
return p[n-1][m-1];
}
此題其實是較簡單的dp問題,難點在於它是動態規劃與概率的結合,只要意識到了到達每個點的概率不同就成功了一半!
最後,總結一點,程式設計更多需要一種邊界思維,好多問題都需要處理好邊界,才能使得**健壯、魯棒,除錯演算法程式最快的就是每一步都要有數學思維的參與,這可以很好地解決指標越界等問題!
錯誤之處,在所難免,不吝賜教!
牛客網 華為機試 020 牛客網
密碼要求 1.長度超過8位 2.包括大小寫字母.數字.其它符號,以上四種至少三種 3.不能有相同長度超2的子串重複 說明 長度超過2的子串 一組或多組長度超過2的子符串。每組佔一行 如果符合要求輸出 ok,否則輸出ng 示例1 021abc9000 021abc9abc1 021abc9000 02...
牛客 2019蘑菇街 方格走法
題目描述 有乙個x y的網格,小團要在此網格上從左上角到右下角,只能走格點且只能向右或向下走。請設計乙個演算法,計算小團有多少種走法。給定兩個正整數int x,int y,請返回小團的走法數目。輸入描述 輸入包括一行,空格隔開的兩個正整數x和y,取值範圍 1,10 輸出描述 輸出一行,表示走法的數目...
牛客網 乳酪
題目很簡單,中文題。複製了 乳酪之間距離不用管,只要開個並查集維護就好了,另外需要選好幾個點作為起點幾個點作為終點。o n 2 的建圖。感覺可以平面掃瞄。有空去試試。以下 ac includeusing namespace std const int maxn 1e5 5 define ll lon...