首页 > 其他分享 >P2140 小Z的电力管制

P2140 小Z的电力管制

时间:2022-11-12 19:25:10浏览次数:40  
标签:x1 P2140 电力 33 矩阵 x2 管制 y1 y2

本题的正解为动态规划。

题意:题面讲的已经很清楚了,这里不做多解释。

思路:定义两个四维数组 f1f1 和 f2f2,f1_{x1,y1,x2,y2}f1x1,y1,x2,y2​ 表示左上角坐标为 (x1,y1)(x1,y1),右下角坐标为 (x2,y2)(x2,y2) 的矩阵划分区域数的最大值,f2f2 记录在保证划分区域数最大的情况下能够剩余电力的最大值。定义变量 sumsum 表示电力需求总和 -− uu,我们需要保证划分后的任意一个区域的电力需求 \ge sum≥sum。

对于任意一个矩阵,我们只需要考虑它由哪两个矩阵转移过来(即横切和竖切),在转移的过程中,更新 f2f2 数组的值。

初始化:每枚举到一个矩阵,如果这个矩阵的权值 \ge sum≥sum(矩阵的权值即为矩阵中的所有数相加),就将 f1f1 初始化为 11,f2f2 赋值为这个矩阵的权值,这里的矩阵权值可以用前缀和实现。

实现步骤:

  1. 枚举矩阵 (x1,y1,x2,y2)(x1,y1,x2,y2),如果这个矩阵满足权值和 \ge sum≥sum,初始化,否则跳出枚举下一个矩阵。
  2. 横切:kk 枚举矩阵的每一行,分割线在第 kk 行和第 k+1k+1 行之间,分割后的两个矩阵为 (x1,y1,k,y2)(x1,y1,k,y2) 和 (k+1,y1,x2,y2)(k+1,y1,x2,y2),如果这两个矩阵的 f1f1 值都 \ge 1≥1,表示可以分割,更新 f1_{x1,y1,x2,y2}f1x1,y1,x2,y2​ 和 f2_{x1,y1,x2,y2}f2x1,y1,x2,y2​ 的值。代码如下:
    if(f1[x1][y1][x2][y2]<f1[x1][y1][k][y2]+f1[k+1][y1][x2][y2]){
        f1[x1][y1][x2][y2]=f1[x1][y1][k][y2]+f1[k+1][y1][x2][y2];
        f2[x1][y1][x2][y2]=min(f2[x1][y1][k][y2],f2[k+1][y1][x2][y2]);
    }
    else if(f1[x1][y1][x2][y2]==f1[x1][y1][k][y2]+f1[k+1][y1][x2][y2])
        f2[x1][y1][x2][y2]=max(f2[x1][y1][x2][y2],min(f2[x1][y1][k][y2],f2[k+1][y1][x2][y2]));
  3. 竖切:思路和横切一样,把 kk 枚举行变为枚举列,分割后的两个矩阵变为 (x1,y1,x2,k)(x1,y1,x2,k) 和 (x1,k+1,x2,y2)(x1,k+1,x2,y2) 就好了。

时间复杂度:一共 55 层循环,时间复杂度为 O(n^5)O(n5),对于 n \le 32n≤32 的数据是完全可以通过的。

code

#include<bits/stdc++.h>
using namespace std;
int n,m,u,sum=0;
int a[33][33];
int f1[33][33][33][33],f2[33][33][33][33],s[33][33];
int main(){
    scanf("%d%d%d",&n,&m,&u);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            scanf("%d",&a[i][j]);
            sum+=a[i][j];
            s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j];//前缀和
        }
    sum-=u;
    for(int len1=1;len1<=n;len1++)//前两层枚举矩阵的大小 
        for(int len2=1;len2<=m;len2++)
            for(int x1=1,x2=x1+len1-1;x2<=n;x1++,x2++)//枚举矩阵左上角的坐标 
                for(int y1=1,y2=y1+len2-1;y2<=m;y1++,y2++){
                    int su=s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1];
                    if(su<sum) continue;
                    f1[x1][y1][x2][y2]=1;
                    f2[x1][y1][x2][y2]=su-sum;//初始化 
                    for(int k=x1;k<x2;k++){//横切 
                        if(!(f1[x1][y1][k][y2]&&f1[k+1][y1][x2][y2])) continue;
                        if(f1[x1][y1][x2][y2]<f1[x1][y1][k][y2]+f1[k+1][y1][x2][y2]){
                            f1[x1][y1][x2][y2]=f1[x1][y1][k][y2]+f1[k+1][y1][x2][y2];
                            f2[x1][y1][x2][y2]=min(f2[x1][y1][k][y2],f2[k+1][y1][x2][y2]);
                        }
                        else if(f1[x1][y1][x2][y2]==f1[x1][y1][k][y2]+f1[k+1][y1][x2][y2])
                            f2[x1][y1][x2][y2]=max(f2[x1][y1][x2][y2],min(f2[x1][y1][k][y2],f2[k+1][y1][x2][y2]));
                    }
                    for(int k=y1;k<y2;k++){//竖切 
                        if(!(f1[x1][y1][x2][k]&&f1[x1][k+1][x2][y2])) continue;
                        if(f1[x1][y1][x2][y2]<f1[x1][y1][x2][k]+f1[x1][k+1][x2][y2]){
                            f1[x1][y1][x2][y2]=f1[x1][y1][x2][k]+f1[x1][k+1][x2][y2];
                            f2[x1][y1][x2][y2]=min(f2[x1][y1][x2][k],f2[x1][k+1][x2][y2]);
                        }
                        else if(f1[x1][y1][x2][y2]==f1[x1][y1][x2][k]+f1[x1][k+1][x2][y2])
                            f2[x1][y1][x2][y2]=max(f2[x1][y1][x2][y2],min(f2[x1][y1][x2][k],f2[x1][k+1][x2][y2]));
                    }
                }
    printf("%d %d\n",f1[1][1][n][m],f2[1][1][n][m]);
    return 0;
}

  

标签:x1,P2140,电力,33,矩阵,x2,管制,y1,y2
From: https://www.cnblogs.com/-111-/p/16884443.html

相关文章