棋盘分割 (经典区间dp)

将一个8*8的棋盘进行如下分割:将原棋盘割下一块矩形棋盘并使剩下部分也是矩形,再将剩下的部分继续如此分割,这样割了(n-1)次后,连同最后剩下的矩形棋盘共有n块矩形棋盘。(每次切割都只能沿着棋盘格子的边进行) 

棋盘分割 (经典区间dp)_第1张图片


原棋盘上每一格有一个分值,一块矩形棋盘的总分为其所含各格分值之和。现在需要把棋盘按上述规则分割成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)_第2张图片

题解:简单区间dp,dp[i][ri][j][rj][d] 表示矩形(左上点(i, j) 右下点(ri, rj)),分成d块的最小和平方和

//#include"bits/stdc++.h"
//#include
//#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
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 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

 

你可能感兴趣的:(动态规划区间dp)