• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

llwwll

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

最大子矩阵之和

最大子矩阵和

分析

一道dp题
观察数据 \(1\le m\le 2\)
先考虑\(m=1\)的情况 相当于一个数组求\(k\)个最大子序列

\(n^2k\)做法

\(dp[i][j]\)表示当前到第\(i\)个有\(j\)组 每次决策时有选或不选两种操作
不选时直接从上一个继承 $$dp[i][j]=dp[i-1][j]$$
选时从小于\(i\)的节点继承$$dp[i][j]=dp[k][j-1]+sum[i]-sum[k]$$

有了\(m=1\)的做法\(\quad\) 类比\(m=2\) 相当于两个数组同时进行上述操作
\(dp[i][j][k]\) 表示第一列\(i\)个\(\quad\)第二列\(j\)个\(\quad\) 选了\(k\)个时
同理$$dp[i][j][k]=max(dp[i-1][j][k],dp[l][j][k-1]+sumA[i]-sumA[l])$$

\[dp[i][j][k]=max(dp[i][j-1][k],dp[i][l][k-1]+sumB[i]-sumB[l]) \]

除此之外
当\(i=j\)时该矩阵可以一起选择
此时有(即\(\quad\)将\(l\)到\(i,j\)的矩阵都选了)$$dp[i][j][k]=max(dp[l][l][k-1]+sumA[i]-sumA[l]+sumB[j]-sumB[l])$$
然后就没有然后了

点击查看代码
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define maxn 10010
#define int long long
using namespace std;
int sum[maxn],dp[maxn][10],a[maxn],pre[maxn],vis[maxn];
//bool cmp(node a,node b){return a.val>b.val;}

int solve(int x,int K)
{
	for(int i=1;i<=x;i++)
	{
		scanf("%lld",&a[i]);	
		sum[i]=sum[i-1]+a[i];
	}
	for(int k=1;k<=K;k++)
	{
		for(int i=1;i<=x;i++)
		{
			dp[i][k]=dp[i-1][k];
			for(int j=0;j<=i;j++)
			{
				dp[i][k]=max(dp[i][k],dp[j][k-1]+sum[i]-sum[j]);
			}
		}
	} 
	return dp[x][K];
}
int b[maxn],suma[maxn],sumb[maxn],f[110][110][11];
int solve2(int x,int K)
{
	for(int i=1;i<=x;i++)
	{
		scanf("%lld%lld",&a[i],&b[i]);	
		suma[i]=suma[i-1]+a[i];
		sumb[i]=sumb[i-1]+b[i];
	}
	for(int k=1;k<=K;k++)
	{
		for(int i=1;i<=x;i++)
		{
			for(int j=1;j<=x;j++)
			{
				f[i][j][k]=max(f[i-1][j][k],f[i][j-1][k]);
				for(int l=0;l<i;l++) f[i][j][k]=max(f[i][j][k],f[l][j][k-1]+suma[i]-suma[l]);
				for(int l=0;l<j;l++) f[i][j][k]=max(f[i][j][k],f[i][l][k-1]+sumb[j]-sumb[l]);
				if(i==j) for(int l=0;l<i;l++) f[i][j][k]=max(f[i][j][k],f[l][l][k-1]+suma[i]+sumb[i]-sumb[l]-suma[l]);
			}
		}
	}
	return f[x][x][K];
}
int n,m,k;
signed main()
{
	scanf("%lld%lld%lld",&n,&m,&k);
	if(m==1) 
	{
		printf("%lld\n",solve(n,k));
		return 0;
	}
	else 
	{
		printf("%lld",solve2(n,k));
		return 0;
	}
	return 0;
}
/*
6 1 1
3
3
1
1
-2
1


3 2 2 
1 -3 
2 3 
-2 3

*/

posted on 2022-09-20 16:42  llwwll  阅读(49)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3