一、問題描述
將乙個8*8的棋盤進行如下分割:將原棋盤割下一塊矩形棋盤並使剩下部分也是矩形,再將剩下的部分繼續如此分割,這樣割了(n-1)次後,連同最後剩下的矩形棋盤共有n塊矩形棋盤。(每次切割都只能沿著棋盤格仔的邊進行)
原棋盤上每一格有乙個分值(小於100的非負整數),一塊矩形棋盤的總分為其所含各格分值之和。現在需要把棋盤按上述規則分割成n塊矩形棋盤,並使各矩形棋盤總分的均方差最小。 (1 < n < 15)
二、解題思路 / n
σ = √∑(xi- x) 2/ n,x = ∑xi / n
x為平均值,把不管如何切割,已經確定了。
我們把標準差公式變形(只考慮根號內):
∑(xi- x) 2/ n = ∑(xi
2 + x2 - 2*xi*x) / n
=( ∑xi
2 + ∑x2 - 2*x*∑xi ) / n
= ( ∑xi
2 + n*x2 - 2*x*nx) / n
= ∑xi
2 / n - x2
所以求標準差的最小值,等價於求平方和的最小值。
用d[k][x1][x2][y1][y2]表示1--x2,y1--y2圍成的矩形切割k次平方和的最小值
橫著切:d[k - 1][x1][a][y1][y2] + sum[a + 1][x2][y1][y2](選上邊,加下邊)
d[k - 1][a + 1][x2][y1][y2] + sum[x1][a][y1][y2](選下邊,加上邊)
豎著切: d[k - 1][x1][x2][y1][b] + sum[x1][x2][b + 1][y2](選右邊,加左邊)
d[k - 1][x1][x2][b + 1][y2] + sum[x1][x2][y1][b](選左邊,加右邊)
k作為階段,初始化k ==0 的情況,即未切,易知d[0][x1][x2][y1][y2] = sum[x1][x2][y1][y2],k從小到大遞推,d[n - 1][0][7][0][7]就是n個塊平方和的最大值。
三、**實現
1 #include2 #include3 #include4 #include5 #include6using
namespace
std;78
const
int inf = 0x3f3f3f3f;9
intn;
10int arr[10][10
];11
int sum[10][10][10][10]; //
sum[x1][x2][y1][y2]表示x1--x2,y1--y2圍成矩形的面積
12int d[20][10][10][10][10]; //
d[k][x1][x2][y1][y2]表示1--x2,y1--y2圍成的矩形切割k次平方和的最小值
1314
void
init()
1527}28
29void
slove()
3050}51
52double res = sqrt((double)d[n - 1][0][7][0][7] / n - (double)sum[0][7][0][7] / ((double)n * n)); //
注意開根號,血的教訓啊
53 printf("
%.3lf\n
",res );54}
5556
intmain()
5765 }
四、總結
準確的說,這還是我第一次對數學公式進行化簡求解問題,可見數學歸納、再化簡是解決問題的一種重要方法。
同時,這也是我第一次做三維以上的動態規劃題(雖然與二維三維沒多大區別,但也客服了一點心理恐懼),再次使用遞推解決問題,而不是記憶化搜尋,進一步加深了我對「階段」,也就是各維迴圈順序的理解。
Luogu1436 棋盤分割(動態規劃)
無 將乙個 的棋盤進行如下分割 將原棋盤割下一塊矩形棋盤並使剩下部分也是矩形,再將剩下的兩部分中的任意一塊繼續如此分割,這樣割了 n 1 次後,連同最後剩下的矩形棋盤共有n塊矩形棋盤。每次切割都只能沿著棋盤格仔的邊進行 原棋盤上每一格有乙個分值,一塊矩形棋盤的總分為其所含各格分值之和。現在需要把棋盤...
POJ 1191 棋盤分割 動態規劃
詳見 include include include include include include using namespace std int n,sum 10 10 sum i j 表示以i,j為右下角的矩陣的和 int dp 15 10 10 10 10 int tot 10 10 10 ...
動態規劃 遞迴 poj1191,棋盤分割
明白幾點 1 最終的均方差 2 動歸含義 dp n x1 x2 y1 y2 表示由x1,x2,y1,y2組成的矩形要生成n塊小矩陣,均方差的最小值 sigma i 1 m xi xi 它的值需要遍歷所有橫向切 縱向切的可能,然後取最小值。最終結果是dp n 1 8 1 8 不多說。include i...