動態規劃題解 D001 分田地

2021-08-22 04:34:59 字數 2477 閱讀 4484

題目描述

牛牛和 15 個朋友來玩打土豪分田地的遊戲,牛牛決定讓你來分田地,地主的田地可以看成是乙個矩形,每個位置有乙個價值。分割田地的方法是橫豎各切三刀,分成 16 份,作為領導幹部,牛牛總是會選擇其中總價值最小的乙份田地, 作為牛牛最好的朋友,你希望牛牛取得的田地的價值和盡可能大,你知道這個值最大可以是多少嗎?

輸入描述:

每個輸入包含 1 個測試用例。每個測試用例的第一行包含兩個整數 n 和 m(1 <= n, m <= 75),表示田地的大小,接下來的 n 行,每行包含 m 個 0-9 之間的數字,表示每塊位置的價值

輸出描述:

輸出一行表示牛牛所能取得的最大的價值。

示例1

輸入 4 4

3332

3233

3332

2323

輸出 2

一句話說明,給出乙個矩陣,將這個矩陣切割成16個小矩形(橫向切三次,縱向切三次),得到的目標是16個小矩形中值最小的乙個矩形,求在不同切法中這個最小矩形的最大值。注意示例中給出的是乙個方陣,但事實上矩陣不一定是長寬相等的。

這是乙個較為典型的最小值裡求最大的問題。初看確實沒有什麼思路,最容易的想法當然是暴力搜尋,但很顯然會超時,時間複雜度達到o(n^6);這個時候,當正向找不到思路的時候,我們開始考慮反向的想法:不管最小矩陣的值是多少,它始終是存在乙個範圍的,即介於0-sum[n][m]。這裡的sum[n][m]是指以(0,0)為矩陣左上角座標,(n,m)為矩陣右下角座標的矩陣值,也即最大的矩陣的值之和。那麼,我們是不是可以猜測乙個值value,使得value處理0-sum[n][m]內,這個value值就代表了我們能夠得到的最小矩陣的最大值。在這個基礎上,問題就轉換為了能不能找到這樣一種切法,使得切出的所有子矩陣的值都大於等於value。

由上面的分析可以看到,整個問題可以分解為兩個階段:

第一階段:確定value值

value值的確定相當於是在0-sum[n][m]這個區間內進行搜尋。通過遍歷進行搜尋會出現超時錯誤,因此想到進行二分查詢。isvalid()函式的作用是判斷在當前這個value值的情況下是否能找到合適的切法。設定l初始為0,r初始為sum[n][m],mid為(l+r)/2。有乙個合理的理解為,當value值足夠小時,肯定能找到合適的切法,比如極端情況下,當設定value=0時,不管怎麼切都是可以的。因此isvalid()為假只可能出現在value值偏大的情況下。在這種情況下,二分函式的寫法可以寫為:

while(l<=r)

else

}

第二階段:確定在當前value值下是否有合適的切法

在value值下尋找切割方法較為暴力,即首先利用遍歷的方法尋找行的三個切割點,再在三個切割點的情況下,選擇遍歷列,遍歷列的時候採用了貪心的思想。即當找到第乙個可行的切割點時,就從這個切割點進行切割,以此向後類推:

設定cnt來記錄某一列是否符合條件;對於每一次的列切割結束之後,我們需要統計,如果cnt的值大於等於4,則直接返回true。當遍歷結束所有的情況後仍然沒有返回true後,即返回false。

注意這裡為什麼將cnt的值設定為4,這是因為需要劃分為16塊,且在行上切三次,列上切三次,切三次意味著列被分為4列,故cnt的值被設定為4。

疑問:為什麼這個地方對列進行處理的時候可以使用貪心演算法?這樣會導致比如說某一類的情況被忽略掉嗎?這個問題我還沒有想明白。

**:

#include

#include

#include

using namespace std ;

int n,m ; //n代表行、m代表列

int a[100][100]; //記錄矩陣

intsum[100][100]; //記錄矩陣中各個子矩陣的和

//給定左上角和右下角的座標值,計算這個矩陣內的所有元素的值

int calc(int x1,int y1,int x2,int y2)

int isvalid(int k)

}if(cnt>=4)}}

}return

0 ;}

int main()

}//sum矩陣的初始化

memset(sum,0,sizeof(sum)) ;

//計算各個小矩陣的值

for(int i=1;i<=n;i++)

}int l = 0;

int r = sum[n][m];

int mid;

int ans;

//採用二分查詢進行搜尋,關鍵的核心在於isvalid()函式

while(l<=r)

else

}printf("%d\n",ans);

return

0;}

動態規劃專題 解題報告 D

我們先來想想n2 怎麼做,兩個n2 迴圈乙個求以i結尾的最長上公升子串行,另乙個逆序求一遍,然後列舉i,以i為中間點的長度,迴圈更新結果就有了。是不是很簡單,恭喜你tle。想都不用想必t好嗎?沒有個nlogn演算法怎麼在1e6的資料範圍面前找場子?nlo gn nlogn nlog n做法 我們其實...

Python3 筆記 D 001 異常與斷言

import sys 捕獲異常 可靈活組合 def excep try except try print ex except 捕獲所有異常 print 捕獲異常 try print ex except 通過函式獲取異常資訊 types,value,back sys.exc info 捕獲異常 sys...

題解 動態規劃

目錄全部分 這道題首先不考慮優化,我們該怎麼寫呢?顯然,這是乙個區間dp,我們可以利用記憶化搜尋來寫。1 定義狀態 dp i j 表示前i頭分j段的最小價值。2 狀態轉移方程 ans min ans,value x,i dfs dp i 1,left 1 這個狀態轉移方程和 這道題十分類似。3 然後...