luogu 2331 [SCOI2005]最大子矩阵

题目描述

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

输入格式

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

输出格式

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

输入输出样例

输入 #1
3 2 2
1 -3
2 3
-2 3
输出 #1
9

分析

方法1

O(n3*k):luogu 2331 题解

这题中,空矩阵也算子矩阵

m == 1时dp[前i列][选了j个矩阵],分为选与不选当前格两种,选的时候可以连着前面的当做一个矩阵

m == 2 的做法类比m == 1的做法,

f[第1列选了前i个][第2列选了前j个][选了k个子矩阵] = 最大和

对于当前的要选的子矩阵,选的情况有4种:

1. 不选

2. 选第一列

3.选第二列

3.i==j时两列可以看做一个矩阵

代码:

 1 /***********************
 2 User:Mandy.H.Y
 3 Language:c++
 4 Problem:
 5 Algorithm: 
 6 ***********************/
 7 
 8 #include<bits/stdc++.h>
 9 
10 using namespace std;
11 
12 const int maxn = 105;
13 
14 int n,m,K;
15 int a[105][5];
16 int sum[105][5];
17 int dp[maxn][15];
18 int f[maxn][maxn][15];
19 
20 template<class T>inline void read(T &x){
21     x = 0;bool flag = 0;char ch = getchar();
22     while(!isdigit(ch)) flag |= ch == '-',ch = getchar();
23     while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48),ch = getchar();
24     if(flag) x = -x;
25 }
26 
27 template<class T>void putch(const T x){
28     if(x > 9) putch(x / 10);
29     putchar(x % 10 | 48);
30 }
31 
32 template<class T>void put(const T x){
33     if(x < 0) putchar('-'),putch(-x);
34     else putch(x);
35 }
36 
37 void file(){
38     freopen("2331","r",stdin);
39 }
40 
41 void readdata(){
42     read(n);read(m);read(K);
43     for(int i = 1;i <= n; ++ i){
44         for(int j = 1;j <= m; ++ j){
45             read(a[i][j]);
46             sum[i][j] = sum[i - 1][j] + a[i][j];
47         }
48     }
49 }
50 
51 void work(){
52     if(m == 1){//其实这样没必要,因为可以当m == 2做只是第二列等于0; 
53         for(int i = 1;i <= n; ++ i)
54             for(int j = 1;j <= K; ++ j){ 
55                 dp[i][j] = dp[i-1][j];//不选 
56                 for(int l = 0;l <= i; ++ l)//l可以等于i,空矩阵也算子矩阵
57                     dp[i][j] = max(dp[i][j],dp[l][j-1] + sum[i][1] - sum[l][1]);
58             }
59         put(dp[n][K]);
60     } else {
61         for(int i = 1;i <= n; ++ i)
62             for(int j = 1;j <= n; ++ j)
63                 for(int k = 1;k <= K; ++ k){
64                     f[i][j][k] = max(f[i-1][j][k],f[i][j-1][k]);//不选 
65                     for(int l = 0;l <= i; ++ l)//选第一列 
66                         f[i][j][k] = max(f[i][j][k],f[l][j][k-1] + 
67                                          sum[i][1] - sum[l][1]);
68                     
69                     for(int l = 0;l <= j;++ l)//选第二列 
70                         f[i][j][k] = max(f[i][j][k],f[i][l][k-1] + 
71                                          sum[j][2] - sum[l][2]);
72                     
73                     if(i == j)
74                         for(int l = 0;l <= i; ++ l)//两列一起 
75                             f[i][j][k] = max(f[i][j][k],f[l][l][k-1] + 
76                                              sum[i][1] - sum[l][1] + 
77                                              sum[j][2] - sum[l][2]);
78                 }
79         put(f[n][n][K]);
80     } 
81 }
82 
83 int main(){
84 //    file();
85     readdata();
86     work();
87     return 0;
88 }
O(n^3*k)

猜你喜欢

转载自www.cnblogs.com/Mandy-H-Y/p/11470109.html