小奇的矩陣
【題目背景】
小奇總是在數學課上思考奇怪的問題。
【問題描述】
給定一個n*m的矩陣,矩陣中的每個元素aij爲正整數。
接下來規定
1.合法的路徑初始從矩陣左上角出發,每次只能向右或向下走,終點爲右下角。
2.路徑經過的n+m-1個格子中的元素爲A1,A2…A(n+m-1),Aavg爲Ai的平均數,路徑的V值爲(n+m-1)*∑(Ai-Aavg) ^2
(1<=i<=n+m-1)
求V值最小的合法路徑,輸出V值即可,有多組測試數據。
輸入格式
第一行包含一個正整數T,表示數據組數。
對於每組數據:
第一行包含兩個正整數n和m,表示矩陣的行數和列數。
接下來n行,每行m個正整數aij,描述這個矩陣。
輸出格式
對於每次詢問,輸出一行一個整數表示要求的結果
樣例輸入
1
2 2
1 2
3 4
樣例輸出
14
數據規模
對於30%的數據 n<=10,m<=10
有另外40%的數據 n<=15 m<=15,矩陣中的元素不大於5
對於100%的數據 T<=5,n<=30,m<=30,矩陣中的元素不大於30
看到方差的形式也不能打出GG。
首先容易看出來是一個DP,因爲有明顯的階段性,而且很容易想到有兩維應該用來記錄位置。但是應該記錄什麼呢?是否應該加維數呢?
留給我們的突破口就只有答案的這個式子了,所以其實本題比較好想。對於題面裏的形式顯然是難以處理的,考慮對式子變形。
不妨設
所以現在我們只需要求出對一個給定的
所以定義狀態
要得到最終答案,枚舉
#include<stdio.h>
#include<cstring>
#include<algorithm>
using namespace std;
int N,M,Map[35][35],f[35][35][1805];
long long Ans,Tmp;
int main()
{
int i,j,k,T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&N,&M);
for(i=1;i<=N;i++)
for(j=1;j<=M;j++)
scanf("%d",&Map[i][j]);
for(i=0;i<=N;i++)
for(j=0;j<=M;j++)
for(k=0;k<=1770;k++)f[i][j][k]=1e8;
f[1][1][Map[1][1]]=Map[1][1]*Map[1][1];
for(i=1;i<=N;i++)
for(j=1;j<=M;j++)
{
if(i==1&&j==1)continue;
for(k=Map[i][j];k<=1770;k++)
f[i][j][k]=min(f[i-1][j][k-Map[i][j]],f[i][j-1][k-Map[i][j]])+Map[i][j]*Map[i][j];
}
Ans=1e9;
for(k=0;k<=1770;k++)
{
Tmp=1ll*(N+M-1)*f[N][M][k]-k*k;
if(Ans>Tmp)Ans=Tmp;
}
printf("%lld\n",Ans);
}
}