[SCOI2005]最大子矩阵
题目描述
这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大。注意:选出的k个子矩阵不能相互重叠。
输入格式
第一行为n,m,k(1≤n≤100,1≤m≤2,1≤k≤10),接下来n行描述矩阵每行中的每个元素的分值(每个元素的分值的绝对值不超过32767)。
输出格式
只有一行为k个子矩阵分值之和最大为多少。
样例 #1
样例输入 #1
3 2 2 1 -3 2 3 -2 3
样例输出 #1
9
曲折的心路历程
谨记:记得看数据范围!!!
本人考试时做题,没有看见m只可能为1或2,想了半天,在草稿纸上画了n个矩阵,甚至还写了个随机来生成矩阵。觉得这道题巨难无比。结果考完试,听同学一说,**,m等于1或2!!!
dp解法
代码
#include<bits/stdc++.h>
using namespace std;
const int inf=0x7fffffff;
int n,m,k,a[105][3],dp[105][12][6];
int maxx(int a1,int a2,int a3,int a4,int a5){
int mmax=-1;
mmax=max(mmax,a1);
mmax=max(mmax,a2);
mmax=max(mmax,a3);
mmax=max(mmax,a4);
mmax=max(mmax,a5);
return mmax;
}
int main(){
cin>>n>>m>>k;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>a[i][j];
}
}
for(int i=1;i<=n;i++){
int sum1=a[i][1];
int sum2=a[i][2];
int sum3=a[i][1]+a[i][2];
for(int j=1;j<=k;j++){
dp[i][j][1]=maxx(dp[i-1][j][1],dp[i-1][j][2],dp[i-1][j][3],dp[i-1][j][4],dp[i-1][j][5]);
dp[i][j][2]=maxx(dp[i-1][j-1][1]+sum1,dp[i-1][j][2]+sum1,dp[i-1][j-1][3]+sum1,dp[i-1][j][4]+sum1,dp[i-1][j-1][5]+sum1);
dp[i][j][3]=maxx(dp[i-1][j-1][1]+sum2,dp[i-1][j-1][2]+sum2,dp[i-1][j][3]+sum2,dp[i-1][j][4]+sum2,dp[i-1][j-1][5]+sum2);
dp[i][j][5]=maxx(dp[i-1][j-1][1]+sum3,dp[i-1][j-1][2]+sum3,dp[i-1][j-1][3]+sum3,dp[i-1][j-1][4]+sum3,dp[i-1][j][5]+sum3);
if(j==1) continue;
dp[i][j][4]=maxx(dp[i-1][j-2][1]+sum3,dp[i-1][j-1][2]+sum3,dp[i-1][j-1][3]+sum3,dp[i-1][j][4]+sum3,dp[i-1][j-2][5]+sum3);
}
}
int ans=inf+1;
for(int i=0;i<=k;i++){
for(int j=1;j<=5;j++){
ans=max(ans,dp[n][i][j]);
}
}
cout<<ans;
return 0;
}
其中dp[i][j][1-5]代表当前枚举到第i行,已经放置了j个矩阵,最后一维代表5种情况(如下文)
我们先从m==2开始讨论
这里的dp一共存在5种情况
以图中的一行为例,如果我们枚举到了当前一行(图中红色标记的一行)
第一种情况我们这一行两个元素都要取,如图1
第二种情况是这一行的两个都要取,但不在同一个矩阵内,如图2
第三种情况就是只选左边的元素,如图三
还有对应的只选右边的情况,如图4
最后就是都不选的情况,就不放图了
在dp的时候,这每一种情况都可以和上面已经dp好的元素连在一起,只要我们分析出了这五种情况,就可以写出这巨长的dp方程了
注:上面讲的情况顺序不一定和下面代码顺序相同
dp[i][j][1]=maxx(dp[i-1][j][1],dp[i-1][j][2],dp[i-1][j][3],dp[i-1][j][4],dp[i-1][j][5]);
dp[i][j][2]=maxx(dp[i-1][j-1][1]+sum1,dp[i-1][j][2]+sum1,dp[i-1][j-1][3]+sum1,dp[i-1][j][4]+sum1,dp[i-1][j-1][5]+sum1);
dp[i][j][3]=maxx(dp[i-1][j-1][1]+sum2,dp[i-1][j-1][2]+sum2,dp[i-1][j][3]+sum2,dp[i-1][j][4]+sum2,dp[i-1][j-1][5]+sum2);
dp[i][j][5]=maxx(dp[i-1][j-1][1]+sum3,dp[i-1][j-1][2]+sum3,dp[i-1][j-1][3]+sum3,dp[i-1][j-1][4]+sum3,dp[i-1][j][5]+sum3);
if(j==1) continue;
dp[i][j][4]=maxx(dp[i-1][j-2][1]+sum3,dp[i-1][j-1][2]+sum3,dp[i-1][j-1][3]+sum3,dp[i-1][j][4]+sum3,dp[i-1][j-2][5]+sum3);
需要特别注意的是,代码里的最后一种情况需要特判j是否大于等于2,因为这种情况的转移是j-2,如果不特判要访问越界。
最后统计答案时只用一遍for循坏就够了,本人多写了,别在意
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!