题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=5492
思路:
可以将所求的式子展开,展开后变为(n+m-1)*x1-x2。
x1是序列A的平方和,x2是序列A的和的平方。
所以我只要找到x2相同时,x1最小的那个就行了。
所以可以考虑dp[i][j][k],表示在第i行第j列的时候,序列和为k时候的x1的最小值。
k的值最大为59*30.
那么就有状态转移方程:
向下:dp[i+1][j][k+a[i+1[j]]=min(dp[i+1][j][k+a[i+1][j]],dp[i][j][k]+a[i+1][j]*a[i+1][j]);
向右:dp[i][j+1][k+a[i][j+1]]=min(dp[i][j+1][k+a[i][j+1]],dp[i][j][k]+a[i][j+1]*a[i][j+1]);
注意初始化。dp[1][1][a[1][1]]=a[1]*a[1];
代码:
#include<stdio.h>
#include<string.h>
int min(int a,int b)
{
if(a<b)return a;
else return b;
}
int dp[34][34][2000];
int main()
{
int T,N,M,i,j,k,a[34][34],icase;
scanf("%d",&T);
icase=0;
while(T--)
{
icase++;
memset(a,0,sizeof(a));
scanf("%d%d",&N,&M);
for(i=0;i<34;i++)
for(j=0;j<34;j++)
for(k=0;k<2000;k++)
dp[i][j][k]=99999999;
for(i=1;i<=N;i++)
for(j=1;j<=M;j++)
scanf("%d",&a[i][j]);
dp[1][1][a[1][1]]=a[1][1]*a[1][1];
for(i=1;i<=N;i++)
for(j=1;j<=M;j++)
{
for(k=0;k<=59*30;k++)
{
dp[i+1][j][k+a[i+1][j]]=min(dp[i+1][j][k+a[i+1][j]],dp[i][j][k]+a[i+1][j]*a[i+1][j]);
}
for(k=0;k<=59*30;k++)
dp[i][j+1][k+a[i][j+1]]=min(dp[i][j+1][k+a[i][j+1]],dp[i][j][k]+a[i][j+1]*a[i][j+1]);
}
int mini=99999999;
for(k=0;k<=59*30;k++)
if(mini>dp[N][M][k]*(N+M-1)-k*k&&dp[N][M][k]!=99999999)mini=dp[N][M][k]*(N+M-1)-k*k;
printf("Case #%d: ",icase);
printf("%d\n",mini);
}
return 0;
}
(N+M−1)∑N+M−1i=1(Ai−Aavg)2
(N+M−1)∑N+M−1i=1(Ai−Aavg)2