【SCOI2005】 最大子矩阵 BZOJ 1084

Description

这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大。注意:选出的k个子矩阵不能相互重叠。

Input

第一行为n,m,k(1≤n≤100,1≤m≤2,1≤k≤10),接下来n行描述矩阵每行中的每个元素的分值(每个元素的分值的绝对值不超过32767)。

Output

只有一行为k个子矩阵分值之和最大为多少。

Sample Input

3 2 2
1 -3
2 3
-2 3

Sample Output

9

思路

    看到题目:好难啊。。一点思路都没有。

    然后看到数据范围M<=2,你™在逗我?何必用矩形来吓人呢。。就是两个一维的最大子矩阵问题嘛!

    然后用f[i][j][k]表示第一列用到i,第二列用到j,已经有k个矩形的最大值。

    所以f[i][j][k]=max{f[i'-1][j][k-1]+sum[1][i'][i],f[i][j'-1][k-1]+sum[2][j'][j]}

    当i==j的时候还会有一个转移,就是两行一起形成一个矩形。

     f[i][i][k]=max{f[i'-1][i'-1][k-1]+sum[1][i'][i]+sum[2][i'][i]}

    其中sum[i][j][k]表示第i列从第j个数加到第k个数的和。

    还有一种特殊情况就是全都是负数,或者非负数的个数不够k的,就先选出所有的非负数,然后加上最大的几个负数就行了。

    可是数据里面好像没有这种情况TAT。。伐开森。

  

 1 #include <iostream>
 2 #include <cstring>
 3 #include <string>
 4 #include <cstdio>
 5 #include <cstdlib>
 6 #include <cmath>
 7 #include <algorithm>
 8 #include <queue>
 9 #include <stack>
10 #include <map>
11 #include <set>
12 #include <list>
13 #include <vector>
14 #include <ctime>
15 #include <functional>
16 #define pritnf printf
17 #define scafn scanf
18 #define sacnf scanf
19 #define For(i,j,k) for(int i=(j);i<=(k);(i)++)
20 #define Clear(a) memset(a,0,sizeof(a))
21 using namespace std;
22 typedef unsigned int Uint;
23 const int INF=0x3fffffff;
24 ///==============struct declaration==============
25 
26 ///==============var declaration=================
27 const int MAXN=110;
28 int row,col,k,temp=0;
29 int A[MAXN][10],Sum[MAXN][5];
30 int f[MAXN][MAXN][15];
31 ///==============function declaration============
32 int cmp(int a,int b){return a>b;}
33 ///==============main code=======================
34 int main()
35 {
36 #define FILE__
37 #ifdef FILE__
38    freopen("input","r",stdin);
39    freopen("output","w",stdout);
40 #endif
41    scanf("%d%d%d",&row,&col,&k);
42    int Plus=0;
43    for(int i=1;i<=row;i++)
44       for(int j=1;j<=col;j++){
45          scanf("%d",&A[i][j]);
46          Sum[i][j]=Sum[i-1][j]+A[i][j];
47          if (A[i][j]>=0){
48             Plus++;
49             temp+=A[i][j];
50          }
51       }
52    for(int r1=1;r1<=row;r1++)
53       for(int r2=1;r2<=row;r2++)
54          for(int p=1;p<=k;p++){
55             f[r1][r2][p]=max(f[r1][r2-1][p],f[r1-1][r2][p]);
56             for(int NewR=1;NewR<=max(r1,r2);NewR++){
57                if (NewR<=r1)
58                   f[r1][r2][p]=max(f[r1][r2][p],f[NewR-1][r2][p-1]+Sum[r1][1]-Sum[NewR][1]);
59                if (NewR<=r2)
60                   f[r1][r2][p]=max(f[r1][r2][p],f[r1][NewR-1][p-1]+Sum[r2][2]-Sum[NewR][2]);
61                if (r1==r2){
62                   f[r1][r2][p]=max(f[NewR-1][NewR-1][p-1]+Sum[r1][1]-Sum[NewR][1]+Sum[r2][2]-Sum[NewR][2],f[r1][r2][p]);
63                }
64             }
65          }
66    if (Plus>=k)
67      printf("%d
",f[row][row][k]);
68    else{
69       int Arr[MAXN*2];
70       for(int i=1;i<=row;i++){
71          Arr[i*2-1]=A[i][1];if (Arr[i*2-1]>0) Arr[i*2-1]=-INF;
72          Arr[i*2]=A[i][2];if (Arr[i*2]>0) Arr[i*2]=-INF;
73       }
74       sort(Arr+1,Arr+1+row*2,cmp);
75       for(int i=Plus+1;i<=k;i++)
76          temp+=Arr[i-Plus];
77       printf("%d
",temp);
78    }
79    return 0;
80 }
81 ///================fuction code====================
BZOJ 1084
原文地址:https://www.cnblogs.com/Houjikan/p/4323708.html