DP专题——棋盘分割

Posted nelson992770019

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DP专题——棋盘分割相关的知识,希望对你有一定的参考价值。

题目:https://www.luogu.org/problem/P1436

题目描述

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

技术图片

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

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

输入格式

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

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

输出格式

仅一个数,为平方和。

  一道典型的dp题,思路很简单,我们用(a,b,c,d)来描述左上角为(a,b),右下角为(c,d)的矩形,对于每个矩形,我们考虑竖着切一刀or横着切一刀,每次考虑切下来的两块哪一块作为下次切的对象即可。

  优化:用sum[i][j]描述(1,1,i,j)的面积,求某个矩形面积用容斥即可。

上代码:

 

 1 #include<iostream>
 2 #include<cstdio> 
 3 #include<cmath>
 4 using namespace std;
 5 const int inf=1e9;
 6 int n;
 7 int ma[20][20];
 8 int sum[20][20];
 9 int dp[20][20][20][20][20];
10 int cal(int a,int b,int c,int d)
11     return sum[c][d]+sum[a-1][b-1]-sum[c][b-1]-sum[a-1][d];
12 
13 int main()
14     scanf("%d",&n);
15     for(int i=1;i<=8;i++)
16         for(int j=1;j<=8;j++)
17             scanf("%d",&ma[i][j]);
18             sum[i][j]=sum[i-1][j]+sum[i][j-1]+ma[i][j]-sum[i-1][j-1];
19         
20     
21     for(int a=1;a<=8;a++)
22         for(int b=1;b<=8;b++)
23             for(int c=a;c<=8;c++)
24                 for(int d=b;d<=8;d++)
25                     dp[a][b][c][d][0]+=cal(a,b,c,d);
26                     dp[a][b][c][d][0]*=dp[a][b][c][d][0];
27                 
28             
29         
30     
31     for(int t=1;t<n;t++)
32     for(int a=1;a<=8;a++)
33         for(int b=1;b<=8;b++)
34             for(int c=a;c<=8;c++)
35                 for(int d=b;d<=8;d++)
36                     int q=inf;
37                     for(int y=b;y<d;y++)
38                         q=min(q,min(dp[a][b][c][y][0]+dp[a][y+1][c][d][t-1],dp[a][y+1][c][d][0]+dp[a][b][c][y][t-1]));
39                     
40                     for(int x=a;x<c;x++)
41                         q=min(q,min(dp[x+1][b][c][d][0]+dp[a][b][x][d][t-1],dp[x+1][b][c][d][t-1]+dp[a][b][x][d][0]));//这两句容易错,注意考虑切入点与区间关系
42                     
43                     dp[a][b][c][d][t]=q;
44                 
45             
46         
47     
48 //     for(int i=1;i<=8;i++)
49 //        for(int j=1;j<=8;j++)
50 //            cout<<sum[i][j]<<" ";
51 //        
52 //        cout<<endl;
53 //    
54     cout<<dp[1][1][8][8][n-1]<<endl;
55     return 0;
56  

 

以上是关于DP专题——棋盘分割的主要内容,如果未能解决你的问题,请参考以下文章

[DP专题]悬线法

dp暑假专题 训练记录

POJ 1191 棋盘分割(DP)

数位dp专题

区间dp专题练习

LeetCode dp专题