動態規劃 打家劫舍彙總

2021-10-09 09:04:25 字數 4558 閱讀 6309

你是乙個專業的小偷,計畫偷竊沿街的房屋。每間房內都藏有一定的現金,影響你偷竊的唯一制約因素就是相鄰的房屋裝有相互連通的防盜系統,如果兩間相鄰的房屋在同一晚上被小偷闖入,系統會自動報警。給定乙個代表每個房屋存放金額的非負整數陣列,計算你不觸動警報裝置的情況下 ,一夜之內能夠偷竊到的最高金額。

[分析]

題目要求兩間相鄰的房屋不能同時闖入,所以,對於每間房屋都有兩種選擇:搶或不搶。

[**實現]

方法1:遞迴函式定義:考慮偷取[0,…index]房屋能獲得的最大值

vector<

int> memo;

//備忘錄

inttryrob

(vector<

int>

& nums,

int index)

//2、狀態轉移:f(x)=max(偷取index能獲得的最大值:nums[index]+f(index-2),不偷取index能獲得的最大值:f(index-1))

ans =

max(

tryrob

(nums,index-1)

,nums[index]

+tryrob

(nums,index-2)

);memo[index]

= ans;

return ans;

}int

rob(vector<

int>

& nums)

方法2:遞迴函式定義:考慮偷取[index,…n-1]房屋能獲得的最大值

vector<

int> memo;

inttryrob

(vector<

int>

& nums,

int index)

//2、狀態轉移:f(x)=max(偷取index能獲得的最大值:nums[index]+f(index+2),不偷取index能獲得的最大值:f(index+1))

ans =

max(

tryrob

(nums,index+1)

,nums[index]

+tryrob

(nums,index+2)

);memo[index]

= ans;

return ans;

}public

:int

rob(vector<

int>

& nums)

方法3:狀態的定義:考慮偷取[0,…index]房屋能獲得的最大值

int

rob(vector<

int>

& nums)

//2、狀態轉移,i:f(i) = max(偷,不偷)

for(

int i=

1;isize()

;i++

) dp[i]

=max

(dp[i-1]

,nums[i]

+(i-

2>=

0?dp[i-2]

:0))

;return dp[nums.

size()

-1];

}

方法4:狀態的定義:考慮偷取[index,…n-1]房屋能獲得的最大值

int

rob(vector<

int>

& nums)

}//2、狀態轉移,i:f(i) = max(偷,不偷)

for(

int i=n-

2;i>=

0;i--

) dp[i]

=max

(dp[i+1]

,nums[i]

+(i+

2:0))

;return dp[0]

;}

你是乙個專業的小偷,計畫偷竊沿街的房屋,每間房內都藏有一定的現金。這個地方所有的房屋都圍成一圈,這意味著第乙個房屋和最後乙個房屋是緊挨著的。同時,相鄰的房屋裝有相互連通的防盜系統,如果兩間相鄰的房屋在同一晚上被小偷闖入,系統會自動報警

給定乙個代表每個房屋存放金額的非負整數陣列,計算你在不觸動警報裝置的情況下,能夠偷竊到的最高金額。

選取上面方法4的解題思路

狀態的定義:考慮偷取[index,…n-1]房屋能獲得的最大值

狀態的轉移:dp[i] = max(dp[i+1](不搶), nums[i]+dp[i+2]())

相比較於第一道題,這些房子不是一排而是圍成了乙個圈,也就是說,第一間房子和最後一間房子相當於也是相鄰的,不能同時搶。

首尾房間不能同時被搶,那麼就相當於三種情況,要麼都不被搶;要麼第一間房子被搶,最後一間房子不被搶;要麼最後一間房子被搶,第一間房子不被搶,因為後兩種情況肯定比第一種情況打,所以只需要比較第三四種情況即可

int

tryrob

(vector<

int>

& nums,

int start,

int end)

return dp[start];}

introb

(vector<

int>

& nums)

在上次打劫完一條街道之後和一圈房屋後,小偷又發現了乙個新的可行竊的地區。這個地區只有乙個入口,我們稱之為「根」。 除了「根」之外,每棟房子有且只有乙個「父「房子與之相連。一番偵察之後,聰明的小偷意識到「這個地方的所有房屋的排列類似於一棵二叉樹」。如果兩個直接相連的房子在同一天晚上被打劫,房屋將自動報警

計算在不觸動警報的情況下,小偷一晚能夠盜取的最高金額。

方法1:

遞迴函式的定義:對於每個節點設定[搶,不搶]兩種狀態,所能獲得的最大值。(加入記憶化搜尋)

int

tryrob

(treenode* root)

if(root-

>right !=

null

)//不搶當前節點,即進入孩子結點

val =

max(val,

tryrob

(root-

>left)

+tryrob

(root-

>right));

memo[root]

= val;

return val;

}

方法2:

樹形dp問題,使用動態規劃的解法。

當前節點偷或不偷決定了孩子結點偷或不偷,也就是說,我在計算孩子結點的最大值時是依賴於父節點的狀態的,存在後效性。我們可以考慮在設計狀態時,在後面加一維,消除後效性。

狀態的定義:

dp[node][j]:表示以node為根節點的樹,並且規定node是否偷取(j=0不偷,j=1偷)能夠獲得的最大值。

node這一維在每一層就可對應,所以我們只需要在每一層遞迴時,計算dp[0]和dp[1]即可。

狀態的轉移:

dp[0] = max(左結點偷,左節點不偷) + max(右節點偷,右節點不偷)

dp[1] = node->val + 左節點不偷 + 右節點不偷

vector<

int>

tryrob

(treenode* root)

; vector<

int> left =

tryrob

(root-

>left)

;//左子樹所能獲得的最大值

vector<

int> right =

tryrob

(root-

>right)

;//右子樹所能獲得的最大值

vector<

int>dp(

2,0)

;//當前節點不偷獲得的最大值=max(左孩子不偷獲得的最大值,左孩子偷獲得的最大值)+max(右孩子不偷獲得的最大值,右孩子偷獲得的最大值)

dp[0]

=max

(left[0]

, left[1]

)+max(right[0]

, right[1]

);//當前節點偷獲得的最大值=root->val+左孩子不偷獲得的最大值+右孩子不偷獲得的最大值

dp[1]

= root-

>val + left[0]

+ right[0]

;return dp;

}

參考:

[1][2]

動態規劃 打家劫舍

你是乙個專業的小偷,計畫偷竊沿街的房屋。每間房內都藏有一定的現金,影響你偷竊的唯一制約因素就是相鄰的房屋裝有相互連通的防盜系統,如果兩間相鄰的房屋在同一晚上被小偷闖入,系統會自動報警。給定乙個代表每個房屋存放金額的非負整數陣列,計算你在不觸動警報裝置的情況下,能夠偷竊到的最高金額。示例 1 輸入 1...

打家劫舍 動態規劃

你是乙個專業的小偷,計畫偷竊沿街的房屋。每間房內都藏有一定的現金,影響你偷竊的唯一制約因素就是相鄰的房屋裝有相互連通的防盜系統,如果兩間相鄰的房屋在同一晚上被小偷闖入,系統會自動報警。給定乙個代表每個房屋存放金額的非負整數陣列,計算你在不觸動警報裝置的情況下,能夠偷竊到的最高金額。示例 1 輸入 1...

打家劫舍(動態規劃)

打家劫舍 你是乙個專業的小偷,計畫偷竊沿街的房屋。每間房內都藏有一定的現金,影響你偷竊的唯一制約因素就是相鄰的房屋裝有相互連通的防盜系統,如果兩間相鄰的房屋在同一晚上被小偷闖入,系統會自動報警。給定乙個代表每個房屋存放金額的非負整數陣列,計算你在不觸動警報裝置的情況下,能夠偷竊到的最高金額。考慮所有...