P1436 棋盘分割

题目背景

题目描述

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

原棋盘上每一格有一个分值,一块矩形棋盘的总分为其所含各格分值之和。现在需要把棋盘按上述规则分割成n块矩形棋盘,并使各矩形棋盘总分的平方和最小。

请编程对给出的棋盘及n,求出平方和的最小值。

输入格式

第1行为一个整数n(1 < n < 15)。

第2行至第9行每行为8个小于100的非负整数,表示棋盘上相应格子的分值。每行相邻两数之间用一个空格分隔。

输出格式

仅一个数,为平方和。

输入输出样例

输入 #1
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
1460

思路

作者: I_AM_HelloWord

嗯,看数据范围这么小,肯定搞一堆循环暴力dp。

推式子应该不是太难,设dp[k][i][j][p][q]表示从(i,j)到(p,q)中分成k个矩形最小的平方和。

那么初始化就是dp[1][i][j][p][q]=sum(i,j,p,q)^2

至于,sum可以用一个二维前缀和的预处理搞。

考虑一下具体的dp转移过程:

再枚举一个t,表示把i到p行从t行这个分成两块,一块分一次,一块分k-1次,

也表示把j到q列从t列分成两块,一块分一次,一块分k-1次

那么整个方程就很清晰了:

ChkMin(dp[tk][i][j][p][q],min(dp[tk-1][i][j][t-1][q]+dp[1][t][j][p][q],dp[1][i][j][t-1][q]+dp[tk-1][t][j][p][q]));

ChkMin(dp[tk][i][j][p][q],min(dp[tk-1][i][j][p][t-1]+dp[1][i][t][p][q],dp[1][i][j][p][t-1]+dp[tk-1][i][t][p][q]));

代码:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

const int N=8;

int n=8,k;
int a[N][N],s[N][N];
int dp[2*N][N][N][N][N];

int main () {
	memset(dp,0x3f,sizeof(dp));
	scanf("%d",&k);
	for(int i=1; i<=n; i++)
		for(int j=1; j<=n; j++)
			scanf("%d",&a[i][j]);
	for(int i=1; i<=n; i++)
		for(int j=1; j<=n; j++)
			s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j];
	for(int i=1; i<=n; i++)
		for(int j=1; j<=n; j++)
			for(int p=i; p<=n; p++)
				for(int q=j; q<=n; q++) {
					int t=s[p][q]-s[p][j-1]-s[i-1][q]+s[i-1][j-1];
					dp[1][i][j][p][q]=t*t;
				}
	for(int tk=2; tk<=k; tk++)
		for(int i=n; i>=1; i--)
			for(int j=n; j>=1; j--)
				for(int p=i; p<=n; p++)
					for(int q=j; q<=n; q++) {
						for(int t=i+1; t<=p; t++)
							dp[tk][i][j][p][q]=min(dp[tk][i][j][p][q],min(dp[tk-1][i][j][t-1][q]+dp[1][t][j][p][q],dp[1][i][j][t-1][q]+dp[tk-1][t][j][p][q]));
						for(int t=j+1; t<=q; t++)
							dp[tk][i][j][p][q]=min(dp[tk][i][j][p][q],min(dp[tk-1][i][j][p][t-1]+dp[1][i][t][p][q],dp[1][i][j][p][t-1]+dp[tk-1][i][t][p][q]));
					}
	printf("%d\n",dp[k][1][1][n][n]);
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/mysh/p/11639152.html
今日推荐