“人类的历史就是贪心的历史。|

GXYZY

园龄:2年4个月粉丝:0关注:1

[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循坏就够了,本人多写了,别在意

posted @   GXYZY  阅读(18)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起