題目傳送門
給定乙個 \(8×8\) 的棋盤,棋盤的每個小方格都有乙個權值 \(w_x,w_y\)
每次我們可以對棋盤進行一次橫或豎切,將棋盤分成兩塊矩形的子棋盤
分割完一次後,我們可以選擇兩個子棋盤中的乙個再繼續遞迴操作。
可以發現題目中給的這個,右邊這個並不是遞迴下去做的:他對第一次分割的兩個矩形又分別進行了分割(題目要求我們只能保留乙個繼續分割)現需要把棋盤按照上述分割方案,分成 \(n\) 塊(\(n−1\) 次劃分操作)
求乙個劃分方案,使得各子棋盤的總分的均方差最小
不難發現,遞迴操作會有很多冗餘的重複計算,於是我們可以採用記憶化搜尋進行優化
\(f[x_1,y_1,x_2,y_2,k]\) 表示這個區間在剩餘\(k\)刀的情況下,可以獲取到的計算公式最大值
#include using namespace std;
const int n = 10; //8*8個格仔,我們從下標1開始放入,需要用到下標8,開9個。
const int inf = 0x3f3f3f3f;
int n;
int m = 8;
int s[n][n]; //二維字首和
double f[n][n][n][n][n]; //dp結果陣列
double x; //平均值
//二維字首和
int get_sum(int x1, int y1, int x2, int y2)
//均方差公式
double get(int x1, int y1, int x2, int y2)
/** * 功能:記憶化搜尋
* @param x1 左上角x座標
* @param y1 左上角y座標
* @param x2 右下角x座標
* @param y2 右下角y座標
* @param k 剩餘的刀數
* @return 根據公式計算出的最小值
*/double dfs(int x1, int y1, int x2, int y2, int k)
//選擇縱著切
for (int i = y1; i < y2; i++)
//返回打擂台的最小值
return v;
}int main()
//利用二維字首和的結果,計算出平均值,注意要使用double的型別轉換,防止丟失精度
x = (double) s[m][m] / n;
//將dp陣列初始化為負無窮,計算過的》=0 (因為均方差可能為0),未計算過的為-inf
//方便獲取哪個位置是否計算過
memset(f, -0x3f, sizeof f);
//記憶化搜尋:因為最後需要切出n塊矩形棋盤,其實就是需要切n-1刀,開始dfs模擬切每一刀
printf("%.3lf\n", sqrt(dfs(1, 1, 8, 8, n - 1)));
return 0;
}
ACWing 321 棋盤分割
將乙個8 8 8 88 8的棋盤進行如下分割 將原棋盤割下一塊矩形棋盤並使剩下部分也是矩形,再將剩下的部分繼續如此分割,這樣割了 n 1 n 1 n 1 次後,連同最後剩下的矩形棋盤共有n nn塊矩形棋盤。每次切割都只能沿著棋盤格仔的邊進行,例如下面的兩個圖,右圖裡中間豎著切一刀之後,不能繼續在左右...
F 棋盤分割
將乙個 的棋盤進行如下分割 將原棋盤割下一塊矩形棋盤並使剩下部分也是矩形,再將剩下的部分繼續如此分割,這樣割了 n 1 次後,連同最後剩下的矩形棋盤共有n塊矩形棋盤。每次切割都只能沿著棋盤格仔的邊進行 原棋盤上每一格有乙個分值,一塊矩形棋盤的總分為其所含各格分值之和。現在需要把棋盤按上述規則分割成n...
遞迴 棋盤分割問題
language default 棋盤分割 time limit 1000ms memory limit 10000k total submissions 11819 accepted 4175 description 將乙個 的棋盤進行如下分割 將原棋盤割下一塊矩形棋盤並使剩下部分也是矩形,再將剩...