题意:
给
一
个
n
∗
m
的
矩
阵
给一个n*m的矩阵
给一个n∗m的矩阵
找
出
k
个
不
相
交
矩
阵
使
和
最
大
找出k个不相交矩阵使和最大
找出k个不相交矩阵使和最大
求
出
这
个
最
大
和
求出这个最大和
求出这个最大和
题解:
n
<
=
100
,
m
<
=
2
,
k
<
=
10
n<=100,m<=2,k<=10
n<=100,m<=2,k<=10
看
到
这
个
题
先
想
到
的
就
是
一
维
的
最
大
k
个
连
续
子
序
列
和
看到这个题先想到的就是一维的最大k个连续子序列和
看到这个题先想到的就是一维的最大k个连续子序列和
如
果
是
2
个
可
以
进
行
预
处
理
求
值
如果是2个可以进行预处理求值
如果是2个可以进行预处理求值
但
是
如
果
求
k
个
子
序
列
,
那
肯
定
需
要
状
态
转
移
但是如果求k个子序列,那肯定需要状态转移
但是如果求k个子序列,那肯定需要状态转移
列
一
个
d
p
[
n
]
[
k
]
,
前
n
个
数
分
为
k
组
列一个dp[n][k],前n个数分为k组
列一个dp[n][k],前n个数分为k组
转
移
方
程
为
转移方程为
转移方程为
d
p
[
i
]
[
k
]
=
m
a
x
(
d
p
[
i
]
[
k
]
,
d
p
[
j
]
[
k
−
1
]
+
s
u
m
[
i
]
−
s
u
m
[
j
]
)
dp[i][k]=max(dp[i][k],dp[j][k-1]+sum[i]-sum[j])
dp[i][k]=max(dp[i][k],dp[j][k−1]+sum[i]−sum[j])
这
个
d
p
下
来
需
要
O
(
n
2
k
)
,
但
其
实
有
更
快
的
方
法
这个dp下来需要O(n^2k),但其实有更快的方法
这个dp下来需要O(n2k),但其实有更快的方法
但
是
在
这
里
已
经
够
了
,
更
快
的
方
法
可
以
详
见
H
D
U
1024
但是在这里已经够了,更快的方法可以详见HDU1024
但是在这里已经够了,更快的方法可以详见HDU1024
然
后
联
想
到
这
个
题
上
,
看
怎
么
样
能
转
移
到
这
个
题
然后联想到这个题上,看怎么样能转移到这个题
然后联想到这个题上,看怎么样能转移到这个题
首
先
看
到
这
个
数
据
范
围
,
最
先
发
现
的
肯
定
是
这
个
m
的
范
围
首先看到这个数据范围,最先发现的肯定是这个m的范围
首先看到这个数据范围,最先发现的肯定是这个m的范围
m
<
=
2
,
最
多
只
有
两
列
m<=2,最多只有两列
m<=2,最多只有两列
那
说
明
,
对
于
每
一
块
矩
阵
,
要
不
宽
为
1
,
要
不
宽
为
2
那说明,对于每一块矩阵,要不宽为1,要不宽为2
那说明,对于每一块矩阵,要不宽为1,要不宽为2
那
我
们
完
全
可
以
求
出
两
列
的
最
大
k
个
连
续
子
序
列
和
,
然
后
进
行
合
并
那我们完全可以求出两列的最大k个连续子序列和,然后进行合并
那我们完全可以求出两列的最大k个连续子序列和,然后进行合并
同
时
维
护
两
列
,
那
就
可
以
列
出
d
p
[
n
]
[
n
]
[
k
]
同时维护两列,那就可以列出dp[n][n][k]
同时维护两列,那就可以列出dp[n][n][k]
在
第
一
列
选
i
个
,
第
二
列
选
j
个
,
总
共
k
组
的
最
大
值
在第一列选i个,第二列选j个,总共k组的最大值
在第一列选i个,第二列选j个,总共k组的最大值
对
于
每
一
列
的
求
法
,
我
们
用
上
述
的
转
移
方
程
进
行
转
移
对于每一列的求法,我们用上述的转移方程进行转移
对于每一列的求法,我们用上述的转移方程进行转移
现
在
需
要
考
虑
的
是
合
并
的
做
法
现在需要考虑的是合并的做法
现在需要考虑的是合并的做法
就
是
出
现
如
果
有
两
列
可
以
并
在
一
起
比
单
独
一
列
大
的
情
况
就是出现如果有两列可以并在一起比单独一列大的情况
就是出现如果有两列可以并在一起比单独一列大的情况
这
种
情
况
肯
定
是
在
i
,
j
相
等
的
时
候
这种情况肯定是在i,j相等的时候
这种情况肯定是在i,j相等的时候
因
为
是
一
个
矩
阵
,
所
以
找
一
下
上
边
因为是一个矩阵,所以找一下上边
因为是一个矩阵,所以找一下上边
转
移
方
程
为
转移方程为
转移方程为
d
p
[
i
]
[
j
]
[
k
]
=
m
a
x
(
d
p
[
i
]
[
j
]
[
k
]
,
d
p
[
p
]
[
p
]
[
k
−
1
]
,
s
[
i
]
−
s
[
p
]
dp[i][j][k]=max(dp[i][j][k],dp[p][p][k-1],s[i]-s[p]
dp[i][j][k]=max(dp[i][j][k],dp[p][p][k−1],s[i]−s[p]
此
时
的
s
表
示
的
是
两
列
共
同
的
和
,
这
时
候
就
进
行
了
对
两
列
的
合
并
此时的s表示的是两列共同的和,这时候就进行了对两列的合并
此时的s表示的是两列共同的和,这时候就进行了对两列的合并
然
后
按
照
这
个
方
法
进
行
递
推
即
可
,
详
见
代
码
然后按照这个方法进行递推即可,详见代码
然后按照这个方法进行递推即可,详见代码
AC代码
/*
Author:zzugzx
Lang:C++
Blog:blog.csdn.net/qq_43756519
*/
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
#define SZ(x) (int)x.size()
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int mod=1e9+7;
//const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=1e6+10;
const ll inf=0x3f3f3f3f;
const int dir[8][2]={{0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1}};
int a[110][110];
int dp[110][110][20];
int s[110][3];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int n,m,t;
cin>>n>>m>>t;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
cin>>a[i][j];
s[i][j]=s[i-1][j]+a[i][j];
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=t;k++){
dp[i][j][k]=max(dp[i-1][j][k],dp[i][j-1][k]);
for(int p=0;p<i;p++)
dp[i][j][k]=max(dp[i][j][k],dp[p][j][k-1]+s[i][1]-s[p][1]);
for(int p=0;p<j;p++)
dp[i][j][k]=max(dp[i][j][k],dp[i][p][k-1]+s[j][2]-s[p][2]);
if(i==j)
for(int p=0;p<i;p++)
dp[i][j][k]=max(dp[i][j][k],dp[p][p][k-1]+s[i][1]+s[j][2]-s[p][1]-s[p][2]);
}
cout<<dp[n][n][t];
return 0;
}