P1436 棋盘分割

你说的曾经没有我的故事 提交于 2019-11-30 20:03:18

题目背景

题目描述

将一个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;  }  

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!