将一个8*8的棋盘进行如下分割:将原棋盘割下一块矩形棋盘并使剩下部分也是矩形,再将剩下的部分继续如此分割,这样割了(n-1)次后,连同最后剩下的矩形棋盘共有n块矩形棋盘。(每次切割都只能沿着棋盘格子的边进行)
原棋盘上每一格有一个分值,一块矩形棋盘的总分为其所含各格分值之和。现在需要把棋盘按上述规则分割成n块矩形棋盘,并使各矩形棋盘总分的均方差最小。
均方差 ,其中平均值 ,x i为第i块矩形棋盘的总分。
请编程对给出的棋盘及n,求出O'的最小值。
Input
第1行为一个整数n(1 < n < 15)。
第2行至第9行每行为8个小于100的非负整数,表示棋盘上相应格子的分值。每行相邻两数之间用一个空格分隔。
Output
仅一个数,为O'(四舍五入精确到小数点后三位)。
Sample Input
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
Sample Output
1.633
题解:简单区间dp,dp[i][ri][j][rj][d] 表示矩形(左上点(i, j) 右下点(ri, rj)),分成d块的最小和平方和
//#include"bits/stdc++.h"
//#include<unordered_map>
//#include<unordered_set>
#include<iostream>
#include<sstream>
#include<iterator>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<set>
#include<vector>
#include<bitset>
#include<climits>
#include<queue>
#include<iomanip>
#include<cmath>
#include<stack>
#include<map>
#include<ctime>
#include<new>
using namespace std;
#define LL long long
#define ULL unsigned long long
#define MT(a,b) memset(a,b,sizeof(a))
#define lson l, mid, node << 1
#define rson mid + 1, r, node << 1 | 1
const int INF = 0x3f3f3f3f;
const int O = 1e6;
const int mod = 10000;
const int maxn = 1e3+5;
const double PI = acos(-1.0);
const double E = 2.718281828459;
int QAQ = 0;
int Q_Q = 0;
int QWQ = 0;
int U_U = 0;
int O_O = 0;
int OWO = 0;
int X_X = 0;
int QTQ = 0;
int QvQ = 0;
int OvO = 0;
int UwU = 0;
int _ = 1;
int __ = 2;
int ___ = 3;
int ____ = 4;
int _____ = 5;
int ______ = 6;
int _______ = 7;
int ________ = 8;
int _________ = 9;
int main(){
int n; scanf("%d", &n);
int mp[10][10];
for(int i=0; i<8; i++) for(int j=0; j<8; j++) scanf("%d", &mp[i][j]);
int sum[9][9][9][9]; MT(sum, 0);
for(int i=0; i<8; i++) for(int j=0; j<8; j++) {
for(int ri=i; ri<8; ri++) for(int rj=j; rj<8; rj++){
int & ans = sum[i][ri][j][rj];
ans = mp[ri][rj];
if(ri) ans += sum[0][ri-1][0][rj];
if(rj) ans += sum[0][ri][0][rj-1];
if(ri && rj) ans -= sum[0][ri-1][0][rj-1];
if(i) ans -= sum[0][i-1][0][rj];
if(j) ans -= sum[0][ri][0][j-1];
if(i && j) ans += sum[0][i-1][0][j-1];
}
}
int dp[9][9][9][9][2];
for(int d=1; d<=n; d++){
for(int li=1; li<=8; li++) for(int lj=1; lj<=8; lj++){
for(int i=0; i<8; i++) for(int j=0; j<8; j++) {
int rj = j + lj - 1, ri = i + li - 1;
if(rj >= 8 || ri >= 8) break;
int & ans = dp[i][ri][j][rj][d&1] = INF;
if(d == 1) { ans = sum[i][ri][j][rj] * sum[i][ri][j][rj]; continue; }
for(int ki=i; ki<ri; ki++) {
int up = sum[i][ki][j][rj] * sum[i][ki][j][rj];
ans = min(up + dp[ki+1][ri][j][rj][!(d&1)], ans);
int down = sum[ki+1][ri][j][rj] * sum[ki+1][ri][j][rj];
ans = min(down + dp[i][ki][j][rj][!(d&1)], ans);
}
for(int kj=j; kj<rj; kj++){
int left = sum[i][ri][j][kj] * sum[i][ri][j][kj];
ans = min(left + dp[i][ri][kj+1][rj][!(d&1)], ans);
int right = sum[i][ri][kj+1][rj] * sum[i][ri][kj+1][rj];
ans = min(right + dp[i][ri][j][kj][!(d&1)], ans);
}
}
}
}
double ans = sqrt(1.0 * dp[0][7][0][7][n&1] / n - (1.0 * sum[0][7][0][7] / n) * (1.0 * sum[0][7][0][7] / n));
printf("%.3f\n", ans);
return 0;
}