zoukankan      html  css  js  c++  java
  • 【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 } 
    ——抓住了时间,却不会利用的人,终究也逃不过失败的命运。
  • 相关阅读:
    【CodeForces】835D Palindromic characteristics
    【BZOJ】2006: [NOI2010]超级钢琴
    【比赛】STSRM 09
    【比赛】洛谷夏令营NOIP模拟赛
    【BZOJ】4147: [AMPPZ2014]Euclidean Nim
    【BZOJ】3895: 取石子
    【胡策08】解题报告
    【codevs】3196 黄金宝藏
    【BZOJ】1443: [JSOI2009]游戏Game
    【BZOJ】3105: [cqoi2013]新Nim游戏
  • 原文地址:https://www.cnblogs.com/Nelson992770019/p/11247692.html
Copyright © 2011-2022 走看看