牛客網 蘑菇陣

2021-09-30 14:21:28 字數 4272 閱讀 4548

題目描述

現在有兩個好友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...