题目链接
题意
给你一个
n
∗
m
n*m
n∗m 的矩阵,每个节点有个权值,求一个权值和最大的联通块。
连通块还要满足集合不为空,单独行行内也连通
思路
d
p
[
第
i
行
]
[
j
为
左
端
点
]
[
k
为
右
端
点
]
=
最
大
权
值
dp[第i行][j为左端点][k为右端点]=最大权值
dp[第i行][j为左端点][k为右端点]=最大权值
考虑三种转移(存在交集的情况),设上层转移而来区间为
[
q
,
p
]
[q,p]
[q,p]
- q , j < = p < = k q,j<=p<=k q,j<=p<=k, g [ 以 j 为 右 端 点 ] = 上 层 d p 前 缀 最 大 值 , g g [ j ] [ k ] 区 间 = g 最 大 值 g[以j为右端点]=上层dp前缀最大值,gg[j][k]区间=g最大值 g[以j为右端点]=上层dp前缀最大值,gg[j][k]区间=g最大值
- j < = q < = p , k j<=q<=p,k j<=q<=p,k , f [ 以 j 为 左 端 点 ] = 上 层 d p 后 缀 最 大 值 , f f [ j ] [ k ] 区 间 = f 最 大 值 f[以j为左端点]=上层dp后缀最大值,ff[j][k]区间=f最大值 f[以j为左端点]=上层dp后缀最大值,ff[j][k]区间=f最大值
- q < = j < = k < = p q<=j<=k<=p q<=j<=k<=p, w [ j ] [ k ] = 上 层 d p 包 含 [ j , k ] 区 间 的 最 大 值 w[j][k]=上层dp包含[j,k]区间的最大值 w[j][k]=上层dp包含[j,k]区间的最大值
d p [ i ] [ j ] [ k ] = 区 间 和 + m a x ( g g [ j ] [ k ] , f f [ j ] [ k ] , w [ j ] [ k ] ) ; dp[i][j][k] = 区间和+max(gg[j][k],ff[j][k],w[j][k]); dp[i][j][k]=区间和+max(gg[j][k],ff[j][k],w[j][k]);
最后还要满足集合不为空,那么可以将,每次dp值正常求,上层的转移本层的贡献值不低于0。
每个都可以 O ( n 2 ) O(n^2) O(n2)处理,dp需要滚动数组优化空间,区间和用前缀和求,复杂度O(n^3),详见代码。
NB群友直接预处理了包含某个点能选最大值,感觉帮我第三种情况改改也可以做到。。写麻烦了不管了(菜啊)。
代码
#include <bits/stdc++.h>
using namespace std;
template <class T> T mmax(T a, T b) { return max(a,b); }
template <class T, class ...R> T mmax(T a, R... b) { return max(a,mmax(b...)); }
int a[305][305], dp[2][305][305], g[305], gg[305][305], f[305], ff[305][305], w[305][305];
int main() {
#ifdef ONLINE_JUDGE
freopen("livada2.in","r",stdin);
freopen("livada2.out","w",stdout);
#endif
int t;
for(scanf("%d",&t); t; --t) {
int n, m, cur = 1, ans = ~0x3f3f3f3f;
scanf("%d%d",&n,&m);
memset(dp,0,sizeof(dp));
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= m; ++j) scanf("%d",&a[i][j]);
cur ^= 1;
memset(dp[cur],0,sizeof(dp[cur]));
memset(g,0,sizeof(g));
memset(gg,0,sizeof(gg));
memset(f,0,sizeof(f));
memset(ff,0,sizeof(ff));
memset(w,0,sizeof(w));
for(int j = 1; j <= m; ++j) {
for(int k = 1; k <= j; ++k) g[j] = max(dp[cur^1][k][j], g[j]);
}
for(int j = 1; j <= m; ++j) {
for(int k = j; k <= m; ++k) {
gg[j][k] = max(gg[j][k-1],g[k]);
}
}
for(int j = m; j; --j) {
for(int k = m; k >= j; --k) f[j] = max(f[j], dp[cur^1][j][k]);
}
for(int j = 1; j <= m; ++j) {
for(int k = j; k <= m; ++k) {
ff[j][k] = max(ff[j][k-1],f[k]);
}
}
for(int j = 1; j <= m; ++j) {
for(int k = m; k >= j; --k) {
w[j][k] = mmax(w[j-1][k], w[j][k+1], dp[cur^1][j][k]);
}
}
a[i][0] = 0;
for(int j = 1; j <= m; ++j) a[i][j] += a[i][j-1];
for(int j = 1; j <= m; ++j) {
for(int k = j; k <= m; ++k) {
dp[cur][j][k] = a[i][k]-a[i][j-1]+mmax(gg[j][k],ff[j][k],w[j][k]);
ans = max(ans, dp[cur][j][k]);
}
}
}
printf("%d\n",ans);
}
return 0;
}