1191:棋盤分割,考點:遞迴條件
阿新 • • 發佈:2021-07-09
原題:http://bailian.openjudge.cn/practice/1191/
描述
將一個8*8的棋盤進行如下分割:將原棋盤割下一塊矩形棋盤並使剩下部分也是矩形,再將剩下的部分繼續如此分割,這樣割了(n-1)次後,連同最後剩下的矩形棋盤共有n塊矩形棋盤。(每次切割都只能沿著棋盤格子的邊進行)
原棋盤上每一格有一個分值,一塊矩形棋盤的總分為其所含各格分值之和。現在需要把棋盤按上述規則分割成n塊矩形棋盤,並使各矩形棋盤總分的均方差最小。
均方差,其中平均值,xi為第i塊矩形棋盤的總分。
請程式設計對給出的棋盤及n,求出O'的最小值。
輸入
第1行為一個整數n(1 < n < 15)。
第2行至第9行每行為8個小於100的非負整數,表示棋盤上相應格子的分值。每行相鄰兩數之間用一個空格分隔。
輸出
僅一個數,為O'(四捨五入精確到小數點後三位)。
樣例輸入
3 1 1 1 1 1 1 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 0 3
樣例輸出
1.633
解法
首先對均方差的公式進行分析,簡化要算的內容。
設定遞迴函式func(n,x1,y1,x2,y2)表示以(x1,y1)為左上角,(x2,y2)為右下角的棋盤分割成n份後的最小平方和。從n-1份到n份有橫著切、豎著切兩種。
橫著切:上半部分的左上角仍為(x1,y1),右下角為(i,y2);下半部分的左上角為(i+1,y1),右下角為(x2,y2)。n-1份可以在上半部分,也可以在下半部分。
豎著切:左半部分的左上角仍為(x1,y1),右下角為(x2,j);右半部分的左上角為(x1,j+1),右下角為(x2,y2)。n-1份可以在左半部分,也可以在右半部分。
遞迴邊界:無法繼續切的時候
為了避免TLE,用一個表fval來記錄中間結果。(動規)
坑:算平均值的時候用double而不是int,不然會WA
1 #include <iostream> 2 #include <cstring> 3 #include <iomanip> 4 #include <cmath> 5 #define INF 1<<30 6using namespace std; 7 int chess[8][8]; 8 int fval[15][8][8][8][8]; 9 int func(int n, int x1, int y1, int x2, int y2) { 10 if (fval[n][x1][y1][x2][y2] != -1) 11 return fval[n][x1][y1][x2][y2]; 12 if (x2 - x1 + y2 - y1 < n - 1) { 13 fval[n][x1][y1][x2][y2] = INF; 14 return INF; 15 } 16 if (n == 1) { 17 int sum = 0; 18 for(int i=x1;i<=x2;i++) 19 for (int j = y1; j <= y2; j++) { 20 sum += chess[i][j]; 21 } 22 fval[n][x1][y1][x2][y2] = sum * sum; 23 return sum * sum; 24 } 25 int mmin = INF; 26 for (int i = x1; i < x2; i++) { 27 int temp = func(n - 1, x1, y1, i, y2) + func(1, i + 1, y1, x2, y2); 28 if (temp < mmin)mmin = temp; 29 temp = func(1, x1, y1, i, y2) + func(n - 1, i + 1, y1, x2, y2); 30 if (temp < mmin)mmin = temp; 31 } 32 for (int j = y1; j < y2; j++) { 33 int temp = func(n - 1, x1, y1, x2, j) + func(1, x1, j + 1, x2, y2); 34 if (temp < mmin)mmin = temp; 35 temp = func(1, x1, y1, x2, j) + func(n - 1, x1, j + 1, x2, y2); 36 if (temp < mmin)mmin = temp; 37 } 38 fval[n][x1][y1][x2][y2] = mmin; 39 return mmin; 40 } 41 int main() 42 { 43 int n; 44 int sum = 0; 45 cin >> n; 46 for (int i = 0; i < 8; i++) 47 for (int j = 0; j < 8; j++) 48 { 49 cin >> chess[i][j]; 50 sum += chess[i][j]; 51 } 52 memset(fval, -1, sizeof(fval)); 53 int square = func(n, 0, 0, 7, 7); 54 double avg = (double)sum / n;//注意這裡一定要轉換成double,不然會WA 55 double result = square - n * avg*avg; 56 cout << fixed << setprecision(3) << sqrt(result / n) << endl; 57 return 0; 58 }