【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\n",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\n",temp);

78    }

79    return 0;

80 }

81 ///================fuction code====================
BZOJ 1084

 

你可能感兴趣的:(ZOJ)