题解:
选择 k k k个位置交换实际上是一条路径上,有 k k k个属于这条路径上的权值不计贡献,有 k k k个不属于路径的权值计入贡献。所以直接DP, f [ i ] [ j ] [ p ] [ q ] f[i][j][p][q] f[i][j][p][q]表示到了 ( i , j ) (i,j) (i,j),路径上有 p p p个权值不计贡献,在前 i − 1 i-1 i−1行和第 i i i行的前 j j j个没选的权值中有 q q q个权值计入贡献即可。
代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=55;
const int Maxk=25;
const int inf=2147483647;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
int n,m,k,a[Maxn][Maxn],f[Maxn][Maxn][Maxk][Maxk];
int d[Maxn],s[Maxn];
void upd(int &x,int y){x=max(x,y);}
bool cmp(int x,int y){return x>y;}
int main()
{
int T=read();
while(T--)
{
memset(f,-1,sizeof(f));
n=read(),m=read(),k=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
a[i][j]=read();
f[1][1][0][0]=a[1][1];
f[1][1][1][0]=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
int c=0;
for(int l=j+1;l<=m;l++)d[++c]=a[i][l];
for(int l=1;l<j;l++)d[++c]=a[i+1][l];
sort(d+1,d+1+c,cmp);
s[0]=0;
for(int l=1;l<=c;l++)s[l]=s[l-1]+d[l];
for(int p=0;p<=k;p++)
for(int q=0;q<=k;q++)
if(f[i][j][p][q]!=-1)
{
int t=f[i][j][p][q];
if(j<m)
{
upd(f[i][j+1][p][q],t+a[i][j+1]);
if(p<k)upd(f[i][j+1][p+1][q],t);
}
if(i<n)
{
upd(f[i+1][j][p][q],t+a[i+1][j]);
if(p<k)upd(f[i+1][j][p+1][q],t);
for(int l=1;q+l<=k&&l<=c;l++)
{
upd(f[i+1][j][p][q+l],t+a[i+1][j]+s[l]);
if(p<k)upd(f[i+1][j][p+1][q+l],t+s[l]);
}
}
}
}
int ans=0;
for(int i=0;i<=k;i++)upd(ans,f[n][m][i][i]);
printf("%d\n",ans);
}
}