好吧,原文在这里:https://www.luogu.org/problemnew/show/P2258
这道题其实有点恶心,刚开始的时候我还吧题目的意思理解错了!!!
先说55分的做法吧:首先我们要确定选的是哪几行哪几列,这个其实直接用搜索枚举每一种情况,然后求出一个最大值就好了。。。
下面是55分的代码(虽然我不知道多余的拿五分是怎么来的。。。)
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxValue=500000;
int n,m,r,c,a[20][20];
int hang[20],lie[20],num1,num2,sum;
int ans=maxValue;
void findans(int x,int y)
{
if(y==c+1){
int temp=0;
for(int i=1;i<=r;i++){
for(int j=2;j<=c;j++){
temp+=abs(a[hang[i]][lie[j]]-a[hang[i]][lie[j-1]]);
}
}
for(int j=1;j<=c;j++){
for(int i=2;i<=r;i++){
temp+=abs(a[hang[i]][lie[j]]-a[hang[i-1]][lie[j]]);
}
}
ans=min(ans,temp);
return;
}
for(int i=x;i<=m-c+y;i++){
lie[y]=i;
findans(i+1,y+1);
}
}
void dfs(int x,int y)
{
if(y==r+1){
findans(1,1);
return;
}
for(int i=x;i<=n-y+r;++i){
hang[y]=i;
dfs(i+1,y+1);
}
}
int main()
{
cin>>n>>m>>r>>c;
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
cin>>a[i][j];
}
}
dfs(1,1);
cout<<ans<<endl;
return 0;
}
下面说一下动态规划的做法:
首先,在我们确定完行的时候,可以维护一下列。所以我们用f[i][j]代表 选择了i列且最后一列选择原图中第j列的差的绝对值和的最小值。然后在这里需要预处理一下,用w[i]表示第i列行之前的绝对值和 v[i][j]表示第i列到j列间绝对值和。如果不用预处理的话就要再多一重循环(虽然还是可以过,但是要精益求精嘛)
我们先用搜索枚举出每一行的位置,然后先处理掉第一列的绝对值得差。然后再加上之后每一列每行之间的绝对值得差以及这一列和前一列每一行的绝对值的差,所以状态转移方程即为:
f[i][j]=min(f[i][j],f[i-1][k]+w[j]+v[k][j]);
最后附上代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int N = 30;
int f[30][30],a[30][30],dis[30],ans=0x7fffffff;//f[i][j]代表 选择了i列且最后一列选择原图中第j列的差的绝对值和的最小值......
int w[30],v[30][30];//w[i]表示第i列行之前的绝对值和 v[i][j]表示第i列到j列间绝对值和 。。。。。。
int n,m,r,c;
void dp()
{
memset(v,0,sizeof v);
memset(w,0,sizeof w);
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
f[i][j]=0x7fffffff;
}
}
for(int i=1;i<=m;i++)
for(int j=1;j<r;j++)
w[i]+=abs(a[dis[j]][i]-a[dis[j+1]][i]);
for(int i=1;i<=m;i++)
for(int j=i+1;j<=m;j++)
for(int k=1;k<=r;k++)
v[i][j]+=abs(a[dis[k]][i]-a[dis[k]][j]);
f[0][0]=0;
for(int i=1;i<=c;i++)
for(int j=i;j<=m;j++)
for(int k=0;k<j;k++)
f[i][j]=min(f[i][j],f[i-1][k]+w[j]+v[k][j]);
for(int i=c;i<=m;i++)
ans=min(ans,f[c][i]);
}
void dfs(int x,int pre)
{
if(x>r){
dp();
return;
}
for(int i=pre+1;i<=n-r+x;i++){
dis[x]=i;
dfs(x+1,i);
}
}
int main()
{
cin>>n>>m>>r>>c;
for(int i= 1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>a[i][j];
dfs(1,0);
cout<<ans<<endl;
return 0;
}