洛谷 P1436 棋盘分割

如图:

洛谷 P1436 棋盘分割_第1张图片洛谷 P1436 棋盘分割_第2张图片

思路:

这是一个很明显的二维dp题,每一次分割的可以衍生出2种情况:左(上)右(下)2个新矩形

所以最优解一定存在于两种新情况中,继续进行递归求解即可;

dp[左上坐标x][左上坐标y][右下坐标x][右下坐标y][分割次数];

顺推:dp[i][j][k][l][num] -> 新的上(左)(下)(右)矩形dp+   切割零次时剩余部分 sum^2;

逆推:dp[i][j][k][l][num] <- 旧的上(左)(下)(右)矩形dp(需要讨论)+  切割零次时另剩余部分 sum^2;

方程:  

    dp[i][j][k][l][num]=min(横着枚举切割方法,竖着枚举切割方法);//原方程太长,在程序里;

但是这道题的方程并不是最最重要的问题,推出了方程一样T的不要不要的

我们在枚举切割方法的时候,需要求出切割出的矩形的 值的平方,但每次都暴力/自定义函数 算一遍的话太浪费了

于是很流畅的就使得我们想到预处理的办法,利用简单的容斥原理,就可以在dp[i][j][k][l][0]上记录一遍不分割

的时候的平方和。

本蒟蒻是通过求了两遍 前缀和得到的差不多为 O(n^2+n^4)(n=8)算的,因为n不大,所以不是很介意;

总复杂度约为 O(8^5*n次询问+枚举均摊+8^2+8^4) ->O(一个大常数)

#include
using namespace std;
int n,x;
int sum[9][9]; 
int d,b[9][9];
int dp[9][9][9][9][16];
int main(void){
	scanf("%d",&n);
	for(int i=1;i<=8;i++){
		for(int j=1;j<=8;j++){
			scanf("%d",&b[i][j]);
	}}
	for(int i=1;i<=8;i++){
		for(int j=1;j<=8;j++){
		sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+b[i][j];
	}}
	for(int i=1;i<=8;i++){
		for(int j=1;j<=8;j++){
			for(int k=i;k<=8;k++){
				for(int l=j;l<=8;l++){
		d=sum[k][l]-sum[i-1][l]-sum[k][j-1]+sum[i-1][j-1];
		dp[i][j][k][l][0]=d*d;			
	}}}}
	for(int num=1;num


你可能感兴趣的:(dp)