题意:给出一个30 × 30 的矩阵,然后从(1,1)到(n,m),求(n + m - 1) * s1 - s2 * s2的最小值。s1为路径上的点的权值平方和,s2为路径上的点的权值和。
思路:dp[i][j][k]表示和为k的时候平方和最小的值。
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define clr(x,y) memset(x,y,sizeof x)
typedef long long ll;
const int maxn = 30 + 10;
int a[maxn][maxn];
int dp[maxn][maxn][maxn * maxn];
int main()
{
int n,m;
int Tcase;scanf("%d",&Tcase);
for(int ii = 1;ii <= Tcase;ii ++)
{
scanf("%d%d",&n,&m);
for(int i = 1; i <= n;i ++)
for(int j = 1;j <= m;j ++)
scanf("%d",&a[i][j]);
clr(dp,INF);
dp[0][1][0] = dp[1][0][0] = 0;
for(int i = 1;i <= n;i ++)
{
for(int j = 1;j <= m;j ++)
{
for(int k = 0; k < maxn * maxn;k ++)
{
dp[i][j][k] = min(dp[i][j][k],dp[i - 1][j][k - a[i][j]] + a[i][j] * a[i][j]);
dp[i][j][k] = min(dp[i][j][k],dp[i][j - 1][k - a[i][j]] + a[i][j] * a[i][j]);
}
}
}
ll ans = 1e18;
for(int i = 0; i < maxn * maxn; i ++)ans = min(ans,1ll *(n + m - 1) * dp[n][m][i] - 1ll *i * i);
printf("Case #%d: %lld\n",ii,ans);
}
return 0;
}