题目大意:一个最多两列最多100行的数字矩阵,从中选出K个不重叠的矩形,他们的数字之和最大是多少?

https://ac.nowcoder.com/acm/problem/20242

看到最多有两列,可以想到关于每一行的状态进行状态压缩DP,可能状态是:空,左边被占用,右边被占用,左右被不同矩形占用,左右被一个矩形占用。需要维护dp[R][S][N]表示到R行为止处于状态S已经使用N个矩形,最大的和是多少(如果不可能该和为-INF)。状态和个数的转移不难求得,比如dp[5][左右被不同矩形占用][用了5个矩形]可以来自dp[4][空][3], dp[4][左边被占用][4],等等。

int N,M,K;
int score[105][3];
// dp[row][state][count].
int dp[105][10][20];

#define amax(a,b) a=max(a,b)

#define INF 327670000
// state = 0 <=> nothing
// state = 1 <=> left only
// state = 2 <=> right only
// state = 3 <=> left + right
// state = 4 <=> both
int doit() {
  VVI trans = {
    // state = 0
    {0,0,0,0,0},
    // state = 1
    {1,0,1,0,1},
    // state = 2
    {1,1,0,0,1},
    // state = 3
    {2,1,1,0,2},
    // state = 4
    {1,1,1,1,0},
  };
  FOR(row,0,N){
    for (int state = 0; state <= 4; ++state) {
      for (int cnt = 0; cnt <= K; ++cnt) {
        if(row==0){
          if(state==0&&cnt==0){
            dp[row][state][cnt]=0;
          }else{
            dp[row][state][cnt]=-INF;
          }
        } else {
          dp[row][state][cnt]=-INF;
          int cost = 0;
          if (state==1||state==3||state==4){
            cost+=score[row-1][0];
          }
          if(M==2){
            if (state==2||state==3||state==4){
              cost+=score[row-1][1];
            }
          }
          if (state < 2 || M == 2) {
            for (int prev_state=0;prev_state<=4;++prev_state){
              if(cnt>=trans[state][prev_state]){
                dp[row][state][cnt]=max(dp[row][state][cnt],dp[row-1][prev_state][cnt-trans[state][prev_state]]+cost);
              }
            }
          }
        }
        // print(row,state,cnt,dp[row][state][cnt]);
      }
    }
  }
  int ans = -INF;
  for (int state = 0; state <= 4; ++state) {
    amax(ans,dp[N][state][K]);
  }
  return ans;
}

int main(int argc, char* argv[]) {
  read(N,M,K);
  REP(i,N){
    REP(j,M){
      scanf("%d",&score[i][j]);
    }
  }
  printint(doit());
  return 0;
}