Processing math: 100%

洛谷P2331[SCOI2005]最大子矩阵

题目

DP

此题可以分为两个子问题。

m等于1:

原题目转化为求一行数列里的k块区间的和,区间可以为空的值。

直接定义状态dp[i][t]表示前i个数分为t块的最大值。

因为区间可以为空,所以最大值再小也不会比0小,所以初始化dp值为0

有方程dp[i][t]=max(dp[i1][t],dp[j][t1]+ik=j+1a[k])

考虑顺序及边界,发现此时的dp[i][t]是从t1块转移过来的,所以j要和i断开。但是又因为可以从1一路取到i,因此j+1可以取到1。所以0<=j<i,而且t要放在循环的最外面。

m等于2:

同样可以dp,定义状态dp[i][j][t]为第一列取到i,第二列取到j,分为t块的最大值。

有方程dp[i][j][t]=max(dp[i1][j][t],dp[i][j1][t],dp[o][j][t1]+ik=o+1a[k][1],dp[i][o][t1]+jk=o+1a[k][2]);

如果i等于j的话,还有方程

dp[i][j][t]=max(dp[i][j][t],dp[o][o][t1]+ik=o+1a[k][1]+a[k][2]);

顺序及边界和第一问一样。

#include <bits/stdc++.h>
#define N 1001
using namespace std;
int n, m, k, maxn;
int dp[N][N][40], a[N][N], sum1[N], sum2[N], dp1[N][40];
int Max(int a, int b, int c, int d) {return max(max(a, b), max(c, d));}
int Q1(int i, int j)
{
	return sum1[j] - sum1[i - 1];
}
int Q2(int i, int j)
{
	return sum2[j] - sum2[i - 1];
}
int main()
{
	scanf("%d%d%d", &n, &m, &k);
	if (m == 1)
	{
		for (int i = 1; i <= n; i++)
			scanf("%d", &a[i][1]), sum1[i] = sum1[i - 1] + a[i][1];
		for (int t = 1; t <= k; t++)
			for (int i = 1; i <= n; i++)
			{
				dp1[i][t] = dp1[i - 1][t];
				for (int j = 0; j < i; j++)
					dp1[i][t] = max(dp1[i][t], dp1[j][t - 1] + Q1(j + 1, i)); 
			}
		printf("%d", dp1[n][k]);
	}
	else
	{
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= m; j++)
				scanf("%d", &a[i][j]);
		for (int i = 1; i <= n; i++)
			sum1[i] = sum1[i - 1] + a[i][1],
			sum2[i] = sum2[i - 1] + a[i][2]; 	
		for (int i = 1; i <= n; i++)
			dp[i][0][1] = sum1[i], dp[0][i][1] = sum2[i];
	  	for (int t = 1; t <= k; t++)
	 		for (int i = 1; i <= n; i++)
	 			for (int j = 1; j <= n; j++)
	 			{
	 				dp[i][j][t] = max(dp[i - 1][j][t], dp[i][j - 1][t]);
	 				for (int o = 0; o < i; o++)//选择到第i位。
	 					dp[i][j][t] = max(dp[i][j][t], dp[o][j][t - 1] + Q1(o + 1, i));
	 				for (int o = 0; o < j; o++)
	 					dp[i][j][t] = max(dp[i][j][t], dp[i][o][t - 1] + Q2(o + 1, j));
	 				if (i == j)
	 					for (int o = 0; o < i; o++)
	 						dp[i][j][t] = max(dp[i][j][t], dp[o][o][t - 1] + Q1(o + 1, i) + Q2(o + 1, j));
	 			}
		printf("%d", dp[n][n][k]);
 	}
 	return 0;
}
posted @   DAGGGGGGGGGGGG  阅读(125)  评论(0编辑  收藏  举报
编辑推荐:
· 用 .NET NativeAOT 构建完全 distroless 的静态链接应用
· 为什么构造函数需要尽可能的简单
· 探秘 MySQL 索引底层原理,解锁数据库优化的关键密码(下)
· 大模型 Token 究竟是啥:图解大模型Token
· 35岁程序员的中年求职记:四次碰壁后的深度反思
阅读排行:
· 基于Docker+DeepSeek+Dify :搭建企业级本地私有化知识库超详细教程
· 电商平台中订单未支付过期如何实现自动关单?
· 用 .NET NativeAOT 构建完全 distroless 的静态链接应用
· 上周热点回顾(3.31-4.6)
· 爆肝 1 周,为我的白板工具支持了 mermaid 流程图,为 ai 生成流程图铺平道路
点击右上角即可分享
微信分享提示