- 子矩阵(submatrix)
- @ 2026-10-29 21:15:36
回来看看,顺手抢个最优解
ps:这份代码在洛谷也是最优解
#include<bits/stdc++.h>
using namespace std;
const int N=17,INF=0x3f3f3f3f;
int n,m,r,c,a[N][N],sum[N][N],d[N],dp[N][N],ans=INF,sel[N];
int zz[N][N][N],ymq[N][N][N]; //小彩蛋,ymq是zz男朋友的名字缩写哦~
//快读和快写都省略了判断正负的部分,凹点时间
inline int rd()//inline微微提速
{
int x=0;char c=getchar();
while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();//使用位运算代替乘法,加加速
return x;
}
void wr(int x)
{
if(x>9) wr(x/10);
putchar(x%10+'0');
}
void dfs(int dep)
{
if(dep>r)
{
for(int i=1;i<=m;++i)
for(int j=1;j<=c;++j)
dp[i][j]=INF;
for(int i=1;i<=m;++i)dp[i][1]=d[i]; //防止dp[i][1]在循环里多跑,直接预处理
for(int j=2;j<=c;++j)
for(int i=j;i<=m;++i)
{
int mn=INF;
for(int k=j-1;k<i;++k)
if(dp[k][j-1]<INF)
mn=min(mn,dp[k][j-1]+sum[k][i]);
dp[i][j]=mn+d[i];
}
for(int i=c;i<=m;++i)
if(dp[i][c]<ans)//这里理论上可以并到上面的循环里,但zz很懒捏~
ans=dp[i][c];
return;
}
for(int i=(dep==1?1:sel[dep-1]+1);i<=n-(r-dep);++i)//简单剪枝
{
sel[dep]=i;
if(dep>1)//对sum和d数组的处理原本应该放在dfs终止判断里,但zz选择边dfs边预处理,节省时间
{
int p=sel[dep-1];
for(int j=1;j<=m;++j)d[j]+=zz[p][i][j];
}
for(int x=1;x<m;++x)
for(int y=x+1;y<=m;++y)
sum[x][y]+=ymq[x][y][i];
dfs(dep+1);
if(dep>1)//回溯,边dfs边预处理的瓶颈,只要能删掉这个回溯,速度直接翻倍
{
int p=sel[dep-1];
for(int j=1;j<=m;++j)d[j]-=zz[p][i][j];
}
for(int x=1;x<m;++x)
for(int y=x+1;y<=m;++y)
sum[x][y]-=ymq[x][y][i];
}
}
int main()
{
n=rd();m=rd();r=rd();c=rd();
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
a[i][j]=rd();
for(int i=1;i<n;++i)//提前处理好abs运算,以空间换时间
for(int j=i+1;j<=n;++j)//zz和ymq的爱恨情仇qwq
for(int k=1;k<=m;++k)
zz[i][j][k]=zz[j][i][k]=abs(a[i][k]-a[j][k]);
for(int i=1;i<m;++i)
for(int j=i+1;j<=m;++j)
for(int k=1;k<=n;++k)
ymq[i][j][k]=ymq[j][i][k]=abs(a[k][i]-a[k][j]);
dfs(1);
wr(ans);
return 0;
}

2 条评论
-
202609gj10王宇浩 (王宇浩) LV 8 @ 2026-10-31 19:55:23
写代码要细心呐;
第四行的分号是中文的,要改成英文的; -
@ 2026-10-29 22:36:22
这里是zz的小号,QQ号3569070051,欢迎大家加我awa
zz是盛泽二中22届的猫咪学长,快来骚扰他吧qwq
- 1
信息
- ID
- 1520
- 难度
- 9
- 分类
- (无)
- 标签
- 递交数
- 32
- 已通过
- 2
- 通过率
- 6%
- 被复制
- 6
- 上传者